--- /dev/null
+/** @file\r
+Framework PEIM to initialize memory on a Quark Memory Controller.\r
+\r
+Copyright (c) 2013 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "CommonHeader.h"\r
+#include "MrcWrapper.h"\r
+#include <Ioh.h>\r
+#include "Platform.h"\r
+\r
+#include <Library/PlatformHelperLib.h>\r
+\r
+//\r
+// ------------------------ TSEG Base\r
+//\r
+// ------------------------ RESERVED_CPU_S3_SAVE_OFFSET\r
+// CPU S3 data\r
+// ------------------------ RESERVED_ACPI_S3_RANGE_OFFSET\r
+// S3 Memory base structure\r
+// ------------------------ TSEG + 1 page\r
+\r
+#define RESERVED_CPU_S3_SAVE_OFFSET (RESERVED_ACPI_S3_RANGE_OFFSET - sizeof (SMM_S3_RESUME_STATE))\r
+\r
+// Strap configuration register specifying DDR setup\r
+#define QUARK_SCSS_REG_STPDDRCFG 0x00\r
+\r
+// Macro counting array elements\r
+#define COUNT(a) (sizeof(a)/sizeof(*a))\r
+\r
+\r
+EFI_MEMORY_TYPE_INFORMATION mDefaultQncMemoryTypeInformation[] = {\r
+ { EfiReservedMemoryType, EDKII_RESERVED_SIZE_PAGES }, // BIOS Reserved\r
+ { EfiACPIMemoryNVS, ACPI_NVS_SIZE_PAGES }, // S3, SMM, etc\r
+ { EfiRuntimeServicesData, RUNTIME_SERVICES_DATA_SIZE_PAGES },\r
+ { EfiRuntimeServicesCode, RUNTIME_SERVICES_CODE_SIZE_PAGES },\r
+ { EfiACPIReclaimMemory, ACPI_RECLAIM_SIZE_PAGES }, // ACPI ASL\r
+ { EfiMaxMemoryType, 0 }\r
+};\r
+\r
+/**\r
+ Configure Uart mmio base for MRC serial log purpose\r
+\r
+ @param MrcData - MRC configuration data updated\r
+\r
+**/\r
+VOID\r
+MrcUartConfig(\r
+ MRC_PARAMS *MrcData\r
+ )\r
+{\r
+ UINT8 UartIdx;\r
+ UINT32 RegData32;\r
+ UINT8 IohUartBus;\r
+ UINT8 IohUartDev;\r
+\r
+ UartIdx = PcdGet8(PcdIohUartFunctionNumber);\r
+ IohUartBus = PcdGet8(PcdIohUartBusNumber);\r
+ IohUartDev = PcdGet8(PcdIohUartDevNumber);\r
+\r
+ RegData32 = PciRead32 (PCI_LIB_ADDRESS(IohUartBus, IohUartDev, UartIdx, PCI_BASE_ADDRESSREG_OFFSET));\r
+ MrcData->uart_mmio_base = RegData32 & 0xFFFFFFF0;\r
+}\r
+\r
+/**\r
+ Configure MRC from memory controller fuse settings.\r
+\r
+ @param MrcData - MRC configuration data to be updated.\r
+\r
+ @return EFI_SUCCESS MRC Config parameters updated from platform data.\r
+**/\r
+EFI_STATUS\r
+MrcConfigureFromMcFuses (\r
+ OUT MRC_PARAMS *MrcData\r
+ )\r
+{\r
+ UINT32 McFuseStat;\r
+\r
+ McFuseStat = QNCPortRead (\r
+ QUARK_NC_MEMORY_CONTROLLER_SB_PORT_ID,\r
+ QUARK_NC_MEMORY_CONTROLLER_REG_DFUSESTAT\r
+ );\r
+\r
+ DEBUG ((EFI_D_INFO, "MRC McFuseStat 0x%08x\n", McFuseStat));\r
+\r
+ if ((McFuseStat & B_DFUSESTAT_ECC_DIS) != 0) {\r
+ DEBUG ((EFI_D_INFO, "MRC Fuse : fus_dun_ecc_dis.\n"));\r
+ MrcData->ecc_enables = 0;\r
+ } else {\r
+ MrcData->ecc_enables = 1;\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Configure MRC from platform info hob.\r
+\r
+ @param MrcData - MRC configuration data to be updated.\r
+\r
+ @return EFI_SUCCESS MRC Config parameters updated from hob.\r
+ @return EFI_NOT_FOUND Platform Info or MRC Config parameters not found.\r
+ @return EFI_INVALID_PARAMETER Wrong params in hob.\r
+**/\r
+EFI_STATUS\r
+MrcConfigureFromInfoHob (\r
+ OUT MRC_PARAMS *MrcData\r
+ )\r
+{\r
+ PDAT_MRC_ITEM *ItemData;\r
+\r
+ ItemData = (PDAT_MRC_ITEM *)PcdGetPtr (PcdMrcParameters);\r
+\r
+ MrcData->channel_enables = ItemData->ChanMask;\r
+ MrcData->channel_width = ItemData->ChanWidth;\r
+ MrcData->address_mode = ItemData->AddrMode;\r
+ // Enable scrambling if requested.\r
+ MrcData->scrambling_enables = (ItemData->Flags & PDAT_MRC_FLAG_SCRAMBLE_EN) != 0;\r
+ MrcData->ddr_type = ItemData->DramType;\r
+ MrcData->dram_width = ItemData->DramWidth;\r
+ MrcData->ddr_speed = ItemData->DramSpeed;\r
+ // Enable ECC if requested.\r
+ MrcData->rank_enables = ItemData->RankMask;\r
+ MrcData->params.DENSITY = ItemData->DramDensity;\r
+ MrcData->params.tCL = ItemData->tCL;\r
+ MrcData->params.tRAS = ItemData->tRAS;\r
+ MrcData->params.tWTR = ItemData->tWTR;\r
+ MrcData->params.tRRD = ItemData->tRRD;\r
+ MrcData->params.tFAW = ItemData->tFAW;\r
+\r
+ MrcData->refresh_rate = ItemData->SrInt;\r
+ MrcData->sr_temp_range = ItemData->SrTemp;\r
+ MrcData->ron_value = ItemData->DramRonVal;\r
+ MrcData->rtt_nom_value = ItemData->DramRttNomVal;\r
+ MrcData->rd_odt_value = ItemData->SocRdOdtVal;\r
+\r
+ DEBUG ((EFI_D_INFO, "MRC dram_width %d\n", MrcData->dram_width));\r
+ DEBUG ((EFI_D_INFO, "MRC rank_enables %d\n",MrcData->rank_enables));\r
+ DEBUG ((EFI_D_INFO, "MRC ddr_speed %d\n", MrcData->ddr_speed));\r
+ DEBUG ((EFI_D_INFO, "MRC flags: %s\n",\r
+ (MrcData->scrambling_enables) ? L"SCRAMBLE_EN" : L""\r
+ ));\r
+\r
+ DEBUG ((EFI_D_INFO, "MRC density=%d tCL=%d tRAS=%d tWTR=%d tRRD=%d tFAW=%d\n",\r
+ MrcData->params.DENSITY,\r
+ MrcData->params.tCL,\r
+ MrcData->params.tRAS,\r
+ MrcData->params.tWTR,\r
+ MrcData->params.tRRD,\r
+ MrcData->params.tFAW\r
+ ));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+ Configure ECC scrub\r
+\r
+ @param MrcData - MRC configuration\r
+\r
+**/\r
+VOID\r
+EccScrubSetup(\r
+ const MRC_PARAMS *MrcData\r
+ )\r
+{\r
+ UINT32 BgnAdr = 0;\r
+ UINT32 EndAdr = MrcData->mem_size;\r
+ UINT32 BlkSize = PcdGet8(PcdEccScrubBlkSize) & SCRUB_CFG_BLOCKSIZE_MASK;\r
+ UINT32 Interval = PcdGet8(PcdEccScrubInterval) & SCRUB_CFG_INTERVAL_MASK;\r
+\r
+ if( MrcData->ecc_enables == 0 || MrcData->boot_mode == bmS3 || Interval == 0) {\r
+ // No scrub configuration needed if ECC not enabled\r
+ // On S3 resume reconfiguration is done as part of resume\r
+ // script, see SNCS3Save.c ==> SaveRuntimeScriptTable()\r
+ // Also if PCD disables scrub, then we do nothing.\r
+ return;\r
+ }\r
+\r
+ QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_END_MEM_REG, EndAdr);\r
+ QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_START_MEM_REG, BgnAdr);\r
+ QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_NEXT_READ_REG, BgnAdr);\r
+ QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_CONFIG_REG,\r
+ Interval << SCRUB_CFG_INTERVAL_SHIFT |\r
+ BlkSize << SCRUB_CFG_BLOCKSIZE_SHIFT);\r
+\r
+ McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = SCRUB_RESUME_MSG();\r
+}\r
+\r
+/** Post InstallS3Memory / InstallEfiMemory tasks given MrcData context.\r
+\r
+ @param[in] MrcData MRC configuration.\r
+ @param[in] IsS3 TRUE if after InstallS3Memory.\r
+\r
+**/\r
+VOID\r
+PostInstallMemory (\r
+ IN MRC_PARAMS *MrcData,\r
+ IN BOOLEAN IsS3\r
+ )\r
+{\r
+ UINT32 RmuMainDestBaseAddress;\r
+ UINT32 *RmuMainSrcBaseAddress;\r
+ UINTN RmuMainSize;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Setup ECC policy (All boot modes).\r
+ //\r
+ QNCPolicyDblEccBitErr (V_WDT_CONTROL_DBL_ECC_BIT_ERR_WARM);\r
+\r
+ //\r
+ // Find the 64KB of memory for Rmu Main at the top of available memory.\r
+ //\r
+ InfoPostInstallMemory (&RmuMainDestBaseAddress, NULL, NULL);\r
+ DEBUG ((EFI_D_INFO, "RmuMain Base Address : 0x%x\n", RmuMainDestBaseAddress));\r
+\r
+ //\r
+ // Relocate RmuMain.\r
+ //\r
+ if (IsS3) {\r
+ QNCSendOpcodeDramReady (RmuMainDestBaseAddress);\r
+ } else {\r
+ Status = PlatformFindFvFileRawDataSection (NULL, PcdGetPtr(PcdQuarkMicrocodeFile), (VOID **) &RmuMainSrcBaseAddress, &RmuMainSize);\r
+ ASSERT_EFI_ERROR (Status);\r
+ if (!EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_INFO, "Found Microcode ADDR:SIZE 0x%08x:0x%04x\n", (UINTN) RmuMainSrcBaseAddress, RmuMainSize));\r
+ }\r
+\r
+ RmuMainRelocation (RmuMainDestBaseAddress, (UINT32) RmuMainSrcBaseAddress, RmuMainSize);\r
+ QNCSendOpcodeDramReady (RmuMainDestBaseAddress);\r
+ EccScrubSetup (MrcData);\r
+ }\r
+}\r
+\r
+/**\r
+\r
+ Do memory initialisation for QNC DDR3 SDRAM Controller\r
+\r
+ @param FfsHeader Not used.\r
+ @param PeiServices General purpose services available to every PEIM.\r
+\r
+ @return EFI_SUCCESS Memory initialisation completed successfully.\r
+ All other error conditions encountered result in an ASSERT.\r
+\r
+**/\r
+EFI_STATUS\r
+MemoryInit (\r
+ IN EFI_PEI_SERVICES **PeiServices\r
+ )\r
+{\r
+ MRC_PARAMS MrcData;\r
+ EFI_BOOT_MODE BootMode;\r
+ EFI_STATUS Status;\r
+ EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariableServices;\r
+ EFI_STATUS_CODE_VALUE ErrorCodeValue;\r
+ PEI_QNC_MEMORY_INIT_PPI *QncMemoryInitPpi;\r
+ UINT16 PmswAdr;\r
+\r
+ ErrorCodeValue = 0;\r
+\r
+ //\r
+ // It is critical that both of these data structures are initialized to 0.\r
+ // This PEIM knows the number of DIMMs in the system and works with that\r
+ // information. The MCH PEIM that consumes these data structures does not\r
+ // know the number of DIMMs so it expects the entire structure to be\r
+ // properly initialized. By initializing these to zero, all flags indicating\r
+ // that the SPD is present or the row should be configured are set to false.\r
+ //\r
+ ZeroMem (&MrcData, sizeof(MrcData));\r
+\r
+ //\r
+ // Get necessary PPI\r
+ //\r
+ Status = PeiServicesLocatePpi (\r
+ &gEfiPeiReadOnlyVariable2PpiGuid, // GUID\r
+ 0, // INSTANCE\r
+ NULL, // EFI_PEI_PPI_DESCRIPTOR\r
+ (VOID **)&VariableServices // PPI\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Determine boot mode\r
+ //\r
+ Status = PeiServicesGetBootMode (&BootMode);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Initialize Error type for reporting status code\r
+ //\r
+ switch (BootMode) {\r
+ case BOOT_ON_FLASH_UPDATE:\r
+ ErrorCodeValue = EFI_COMPUTING_UNIT_MEMORY + EFI_CU_MEMORY_EC_UPDATE_FAIL;\r
+ break;\r
+ case BOOT_ON_S3_RESUME:\r
+ ErrorCodeValue = EFI_COMPUTING_UNIT_MEMORY + EFI_CU_MEMORY_EC_S3_RESUME_FAIL;\r
+ break;\r
+ default:\r
+ ErrorCodeValue = EFI_COMPUTING_UNIT_MEMORY;\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Specify MRC boot mode\r
+ //\r
+ switch (BootMode) {\r
+ case BOOT_ON_S3_RESUME:\r
+ case BOOT_ON_FLASH_UPDATE:\r
+ MrcData.boot_mode = bmS3;\r
+ break;\r
+ case BOOT_ASSUMING_NO_CONFIGURATION_CHANGES:\r
+ MrcData.boot_mode = bmFast;\r
+ break;\r
+ default:\r
+ MrcData.boot_mode = bmCold;\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Configure MRC input parameters.\r
+ //\r
+ Status = MrcConfigureFromMcFuses (&MrcData);\r
+ ASSERT_EFI_ERROR (Status);\r
+ Status = MrcConfigureFromInfoHob (&MrcData);\r
+ ASSERT_EFI_ERROR (Status);\r
+ MrcUartConfig(&MrcData);\r
+\r
+ if (BootMode == BOOT_IN_RECOVERY_MODE) {\r
+ //\r
+ // Always do bmCold on recovery.\r
+ //\r
+ DEBUG ((DEBUG_INFO, "MemoryInit:Force bmCold on Recovery\n"));\r
+ MrcData.boot_mode = bmCold;\r
+ } else {\r
+\r
+ //\r
+ // Load Memory configuration data saved in previous boot from variable\r
+ //\r
+ Status = LoadConfig (\r
+ PeiServices,\r
+ VariableServices,\r
+ &MrcData\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ switch (BootMode) {\r
+ case BOOT_ON_S3_RESUME:\r
+ case BOOT_ON_FLASH_UPDATE:\r
+ REPORT_STATUS_CODE (\r
+ EFI_ERROR_CODE + EFI_ERROR_UNRECOVERED,\r
+ ErrorCodeValue\r
+ );\r
+ PeiServicesResetSystem ();\r
+ break;\r
+\r
+ default:\r
+ MrcData.boot_mode = bmCold;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Locate Memory Reference Code PPI\r
+ //\r
+ Status = PeiServicesLocatePpi (\r
+ &gQNCMemoryInitPpiGuid, // GUID\r
+ 0, // INSTANCE\r
+ NULL, // EFI_PEI_PPI_DESCRIPTOR\r
+ (VOID **)&QncMemoryInitPpi // PPI\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ PmswAdr = (UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_PMSW;\r
+ if( IoRead32 (PmswAdr) & B_QNC_GPE0BLK_PMSW_DRAM_INIT) {\r
+ // MRC did not complete last execution, force cold boot path\r
+ MrcData.boot_mode = bmCold;\r
+ }\r
+\r
+ // Mark MRC pending\r
+ IoOr32 (PmswAdr, (UINT32)B_QNC_GPE0BLK_PMSW_DRAM_INIT);\r
+\r
+ //\r
+ // Call Memory Reference Code's Routines\r
+ //\r
+ QncMemoryInitPpi->MrcStart (&MrcData);\r
+\r
+ // Mark MRC completed\r
+ IoAnd32 (PmswAdr, ~(UINT32)B_QNC_GPE0BLK_PMSW_DRAM_INIT);\r
+\r
+\r
+ //\r
+ // Note emulation platform has to read actual memory size\r
+ // MrcData.mem_size from PcdGet32 (PcdMemorySize);\r
+\r
+ if (BootMode == BOOT_ON_S3_RESUME) {\r
+\r
+ DEBUG ((EFI_D_INFO, "Following BOOT_ON_S3_RESUME boot path.\n"));\r
+\r
+ Status = InstallS3Memory (PeiServices, VariableServices, MrcData.mem_size);\r
+ if (EFI_ERROR (Status)) {\r
+ REPORT_STATUS_CODE (\r
+ EFI_ERROR_CODE + EFI_ERROR_UNRECOVERED,\r
+ ErrorCodeValue\r
+ );\r
+ PeiServicesResetSystem ();\r
+ }\r
+ PostInstallMemory (&MrcData, TRUE);\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Assign physical memory to PEI and DXE\r
+ //\r
+ DEBUG ((EFI_D_INFO, "InstallEfiMemory.\n"));\r
+\r
+ Status = InstallEfiMemory (\r
+ PeiServices,\r
+ VariableServices,\r
+ BootMode,\r
+ MrcData.mem_size\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ PostInstallMemory (&MrcData, FALSE);\r
+\r
+ //\r
+ // Save current configuration into Hob and will save into Variable later in DXE\r
+ //\r
+ DEBUG ((EFI_D_INFO, "SaveConfig.\n"));\r
+ Status = SaveConfig (\r
+ &MrcData\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ DEBUG ((EFI_D_INFO, "MemoryInit Complete.\n"));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+ This function saves a config to a HOB.\r
+\r
+ @param RowInfo The MCH row configuration information.\r
+ @param TimingData Timing data to be saved.\r
+ @param RowConfArray Row configuration information for each row in the system.\r
+ @param SpdData SPD info read for each DIMM slot in the system.\r
+\r
+ @return EFI_SUCCESS: The function completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SaveConfig (\r
+ IN MRC_PARAMS *MrcData\r
+ )\r
+{\r
+ //\r
+ // Build HOB data for Memory Config\r
+ // HOB data size (stored in variable) is required to be multiple of 8 bytes\r
+ //\r
+ BuildGuidDataHob (\r
+ &gEfiMemoryConfigDataGuid,\r
+ (VOID *) &MrcData->timings,\r
+ ((sizeof (MrcData->timings) + 0x7) & (~0x7))\r
+ );\r
+\r
+ DEBUG ((EFI_D_INFO, "IIO IoApicBase = %x IoApicLimit=%x\n", IOAPIC_BASE, (IOAPIC_BASE + IOAPIC_SIZE - 1)));\r
+ DEBUG ((EFI_D_INFO, "IIO RcbaAddress = %x\n", (UINT32)PcdGet64 (PcdRcbaMmioBaseAddress)));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+ Load a configuration stored in a variable.\r
+\r
+ @param TimingData Timing data to be loaded from NVRAM.\r
+ @param RowConfArray Row configuration information for each row in the system.\r
+\r
+ @return EFI_SUCCESS The function completed successfully.\r
+ Other Could not read variable.\r
+\r
+**/\r
+EFI_STATUS\r
+LoadConfig (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariableServices,\r
+ IN OUT MRC_PARAMS *MrcData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN BufferSize;\r
+ PLATFORM_VARIABLE_MEMORY_CONFIG_DATA VarData;\r
+\r
+ BufferSize = ((sizeof (VarData.timings) + 0x7) & (~0x7)); // HOB data size (stored in variable) is required to be multiple of 8bytes\r
+\r
+ Status = VariableServices->GetVariable (\r
+ VariableServices,\r
+ EFI_MEMORY_CONFIG_DATA_NAME,\r
+ &gEfiMemoryConfigDataGuid,\r
+ NULL,\r
+ &BufferSize,\r
+ &VarData.timings\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ CopyMem (&MrcData->timings, &VarData.timings, sizeof(MrcData->timings));\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+\r
+ This function installs memory.\r
+\r
+ @param PeiServices PEI Services table.\r
+ @param BootMode The specific boot path that is being followed\r
+ @param Mch Pointer to the DualChannelDdrMemoryInit PPI\r
+ @param RowConfArray Row configuration information for each row in the system.\r
+\r
+ @return EFI_SUCCESS The function completed successfully.\r
+ EFI_INVALID_PARAMETER One of the input parameters was invalid.\r
+ EFI_ABORTED An error occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+InstallEfiMemory (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariableServices,\r
+ IN EFI_BOOT_MODE BootMode,\r
+ IN UINT32 TotalMemorySize\r
+ )\r
+{\r
+ EFI_PHYSICAL_ADDRESS PeiMemoryBaseAddress;\r
+ EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *SmramHobDescriptorBlock;\r
+ EFI_STATUS Status;\r
+ EFI_PEI_HOB_POINTERS Hob;\r
+ PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE MemoryMap[MAX_RANGES];\r
+ UINT8 Index;\r
+ UINT8 NumRanges;\r
+ UINT8 SmramIndex;\r
+ UINT8 SmramRanges;\r
+ UINT64 PeiMemoryLength;\r
+ UINTN BufferSize;\r
+ UINTN PeiMemoryIndex;\r
+ UINTN RequiredMemSize;\r
+ EFI_RESOURCE_ATTRIBUTE_TYPE Attribute;\r
+ EFI_PHYSICAL_ADDRESS BadMemoryAddress;\r
+ EFI_SMRAM_DESCRIPTOR DescriptorAcpiVariable;\r
+ VOID *CapsuleBuffer;\r
+ UINTN CapsuleBufferLength;\r
+ PEI_CAPSULE_PPI *Capsule;\r
+ VOID *LargeMemRangeBuf;\r
+ UINTN LargeMemRangeBufLen;\r
+\r
+ //\r
+ // Test the memory from 1M->TOM\r
+ //\r
+ if (BootMode != BOOT_ON_FLASH_UPDATE) {\r
+ Status = BaseMemoryTest (\r
+ PeiServices,\r
+ 0x100000,\r
+ (TotalMemorySize - 0x100000),\r
+ Quick,\r
+ &BadMemoryAddress\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+\r
+ //\r
+ // Get the Memory Map\r
+ //\r
+ NumRanges = MAX_RANGES;\r
+\r
+ ZeroMem (MemoryMap, sizeof (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE) * NumRanges);\r
+\r
+ Status = GetMemoryMap (\r
+ PeiServices,\r
+ TotalMemorySize,\r
+ (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE *) MemoryMap,\r
+ &NumRanges\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Find the highest memory range in processor native address space to give to\r
+ // PEI. Then take the top.\r
+ //\r
+ PeiMemoryBaseAddress = 0;\r
+\r
+ //\r
+ // Query the platform for the minimum memory size\r
+ //\r
+\r
+ Status = GetPlatformMemorySize (\r
+ PeiServices,\r
+ BootMode,\r
+ &PeiMemoryLength\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Get required memory size for ACPI use. This helps to put ACPI memory on the topest\r
+ //\r
+ RequiredMemSize = 0;\r
+ RetriveRequiredMemorySize (PeiServices, &RequiredMemSize);\r
+\r
+ PeiMemoryIndex = 0;\r
+\r
+ for (Index = 0; Index < NumRanges; Index++)\r
+ {\r
+ DEBUG ((EFI_D_INFO, "Found 0x%x bytes at ", MemoryMap[Index].RangeLength));\r
+ DEBUG ((EFI_D_INFO, "0x%x.\n", MemoryMap[Index].PhysicalAddress));\r
+\r
+ if ((MemoryMap[Index].Type == DualChannelDdrMainMemory) &&\r
+ (MemoryMap[Index].PhysicalAddress + MemoryMap[Index].RangeLength < MAX_ADDRESS) &&\r
+ (MemoryMap[Index].PhysicalAddress >= PeiMemoryBaseAddress) &&\r
+ (MemoryMap[Index].RangeLength >= PeiMemoryLength)) {\r
+ PeiMemoryBaseAddress = MemoryMap[Index].PhysicalAddress +\r
+ MemoryMap[Index].RangeLength -\r
+ PeiMemoryLength;\r
+ PeiMemoryIndex = Index;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Find the largest memory range excluding that given to PEI.\r
+ //\r
+ LargeMemRangeBuf = NULL;\r
+ LargeMemRangeBufLen = 0;\r
+ for (Index = 0; Index < NumRanges; Index++) {\r
+ if ((MemoryMap[Index].Type == DualChannelDdrMainMemory) &&\r
+ (MemoryMap[Index].PhysicalAddress + MemoryMap[Index].RangeLength < MAX_ADDRESS)) {\r
+ if (Index != PeiMemoryIndex) {\r
+ if (MemoryMap[Index].RangeLength > LargeMemRangeBufLen) {\r
+ LargeMemRangeBuf = (VOID *) ((UINTN) MemoryMap[Index].PhysicalAddress);\r
+ LargeMemRangeBufLen = (UINTN) MemoryMap[Index].RangeLength;\r
+ }\r
+ } else {\r
+ if ((MemoryMap[Index].RangeLength - PeiMemoryLength) >= LargeMemRangeBufLen) {\r
+ LargeMemRangeBuf = (VOID *) ((UINTN) MemoryMap[Index].PhysicalAddress);\r
+ LargeMemRangeBufLen = (UINTN) (MemoryMap[Index].RangeLength - PeiMemoryLength);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ Capsule = NULL;\r
+ CapsuleBuffer = NULL;\r
+ CapsuleBufferLength = 0;\r
+ if (BootMode == BOOT_ON_FLASH_UPDATE) {\r
+ Status = PeiServicesLocatePpi (\r
+ &gPeiCapsulePpiGuid, // GUID\r
+ 0, // INSTANCE\r
+ NULL, // EFI_PEI_PPI_DESCRIPTOR\r
+ (VOID **)&Capsule // PPI\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ if (Status == EFI_SUCCESS) {\r
+ CapsuleBuffer = LargeMemRangeBuf;\r
+ CapsuleBufferLength = LargeMemRangeBufLen;\r
+\r
+ //\r
+ // Call the Capsule PPI Coalesce function to coalesce the capsule data.\r
+ //\r
+ Status = Capsule->Coalesce (\r
+ PeiServices,\r
+ &CapsuleBuffer,\r
+ &CapsuleBufferLength\r
+ );\r
+ //\r
+ // If it failed, then NULL out our capsule PPI pointer so that the capsule\r
+ // HOB does not get created below.\r
+ //\r
+ if (Status != EFI_SUCCESS) {\r
+ Capsule = NULL;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Set up the IMR policy required for this platform\r
+ //\r
+ Status = SetPlatformImrPolicy (\r
+ PeiMemoryBaseAddress,\r
+ PeiMemoryLength,\r
+ RequiredMemSize\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Carve out the top memory reserved for ACPI\r
+ //\r
+ Status = PeiServicesInstallPeiMemory (PeiMemoryBaseAddress, (PeiMemoryLength - RequiredMemSize));\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ BuildResourceDescriptorHob (\r
+ EFI_RESOURCE_SYSTEM_MEMORY, // MemoryType,\r
+ (\r
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
+ EFI_RESOURCE_ATTRIBUTE_TESTED |\r
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
+ EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |\r
+ EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
+ EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE\r
+ ),\r
+ PeiMemoryBaseAddress, // MemoryBegin\r
+ PeiMemoryLength // MemoryLength\r
+ );\r
+\r
+ //\r
+ // Install physical memory descriptor hobs for each memory range.\r
+ //\r
+ SmramRanges = 0;\r
+ for (Index = 0; Index < NumRanges; Index++) {\r
+ Attribute = 0;\r
+ if (MemoryMap[Index].Type == DualChannelDdrMainMemory)\r
+ {\r
+ if (Index == PeiMemoryIndex) {\r
+ //\r
+ // This is a partially tested Main Memory range, give it to EFI\r
+ //\r
+ BuildResourceDescriptorHob (\r
+ EFI_RESOURCE_SYSTEM_MEMORY,\r
+ (\r
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
+ EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |\r
+ EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
+ EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE\r
+ ),\r
+ MemoryMap[Index].PhysicalAddress,\r
+ MemoryMap[Index].RangeLength - PeiMemoryLength\r
+ );\r
+ } else {\r
+ //\r
+ // This is an untested Main Memory range, give it to EFI\r
+ //\r
+ BuildResourceDescriptorHob (\r
+ EFI_RESOURCE_SYSTEM_MEMORY, // MemoryType,\r
+ (\r
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
+ EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |\r
+ EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
+ EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE\r
+ ),\r
+ MemoryMap[Index].PhysicalAddress, // MemoryBegin\r
+ MemoryMap[Index].RangeLength // MemoryLength\r
+ );\r
+ }\r
+ } else {\r
+ if ((MemoryMap[Index].Type == DualChannelDdrSmramCacheable) ||\r
+ (MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable)) {\r
+ SmramRanges++;\r
+ }\r
+ if ((MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable) ||\r
+ (MemoryMap[Index].Type == DualChannelDdrGraphicsMemoryNonCacheable)) {\r
+ Attribute |= EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE;\r
+ }\r
+ if ((MemoryMap[Index].Type == DualChannelDdrSmramCacheable) ||\r
+ (MemoryMap[Index].Type == DualChannelDdrGraphicsMemoryCacheable)) {\r
+ //\r
+ // TSEG and HSEG can be used with a write-back(WB) cache policy; however,\r
+ // the specification requires that the TSEG and HSEG space be cached only\r
+ // inside of the SMI handler. when using HSEG or TSEG an IA-32 processor\r
+ // does not automatically write back and invalidate its cache before entering\r
+ // SMM or before existing SMM therefore any MTRR defined for the active TSEG\r
+ // or HSEG must be set to un-cacheable(UC) outside of SMM.\r
+ //\r
+ Attribute |= EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE | EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE;\r
+ }\r
+ if (MemoryMap[Index].Type == DualChannelDdrReservedMemory) {\r
+ Attribute |= EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |\r
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE;\r
+ }\r
+ //\r
+ // Make sure non-system memory is marked as reserved\r
+ //\r
+ BuildResourceDescriptorHob (\r
+ EFI_RESOURCE_MEMORY_RESERVED, // MemoryType,\r
+ Attribute, // MemoryAttribute\r
+ MemoryMap[Index].PhysicalAddress, // MemoryBegin\r
+ MemoryMap[Index].RangeLength // MemoryLength\r
+ );\r
+ }\r
+ }\r
+\r
+ //\r
+ // Allocate one extra EFI_SMRAM_DESCRIPTOR to describe a page of SMRAM memory that contains a pointer\r
+ // to the SMM Services Table that is required on the S3 resume path\r
+ //\r
+ ASSERT (SmramRanges > 0);\r
+ BufferSize = sizeof (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK);\r
+ BufferSize += ((SmramRanges - 1) * sizeof (EFI_SMRAM_DESCRIPTOR));\r
+\r
+ Hob.Raw = BuildGuidHob (\r
+ &gEfiSmmPeiSmramMemoryReserveGuid,\r
+ BufferSize\r
+ );\r
+ ASSERT (Hob.Raw);\r
+\r
+ SmramHobDescriptorBlock = (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *) (Hob.Raw);\r
+ SmramHobDescriptorBlock->NumberOfSmmReservedRegions = SmramRanges;\r
+\r
+ SmramIndex = 0;\r
+ for (Index = 0; Index < NumRanges; Index++) {\r
+ if ((MemoryMap[Index].Type == DualChannelDdrSmramCacheable) ||\r
+ (MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable)\r
+ ) {\r
+ //\r
+ // This is an SMRAM range, create an SMRAM descriptor\r
+ //\r
+ SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalStart = MemoryMap[Index].PhysicalAddress;\r
+ SmramHobDescriptorBlock->Descriptor[SmramIndex].CpuStart = MemoryMap[Index].CpuAddress;\r
+ SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalSize = MemoryMap[Index].RangeLength;\r
+ if (MemoryMap[Index].Type == DualChannelDdrSmramCacheable) {\r
+ SmramHobDescriptorBlock->Descriptor[SmramIndex].RegionState = EFI_SMRAM_CLOSED | EFI_CACHEABLE;\r
+ } else {\r
+ SmramHobDescriptorBlock->Descriptor[SmramIndex].RegionState = EFI_SMRAM_CLOSED;\r
+ }\r
+\r
+ SmramIndex++;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Build a HOB with the location of the reserved memory range.\r
+ //\r
+ CopyMem(&DescriptorAcpiVariable, &SmramHobDescriptorBlock->Descriptor[SmramRanges-1], sizeof(EFI_SMRAM_DESCRIPTOR));\r
+ DescriptorAcpiVariable.CpuStart += RESERVED_CPU_S3_SAVE_OFFSET;\r
+ BuildGuidDataHob (\r
+ &gEfiAcpiVariableGuid,\r
+ &DescriptorAcpiVariable,\r
+ sizeof (EFI_SMRAM_DESCRIPTOR)\r
+ );\r
+\r
+ //\r
+ // If we found the capsule PPI (and we didn't have errors), then\r
+ // call the capsule PEIM to allocate memory for the capsule.\r
+ //\r
+ if (Capsule != NULL) {\r
+ Status = Capsule->CreateState (PeiServices, CapsuleBuffer, CapsuleBufferLength);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+ Find memory that is reserved so PEI has some to use.\r
+\r
+ @param PeiServices PEI Services table.\r
+ @param VariableSevices Variable PPI instance.\r
+\r
+ @return EFI_SUCCESS The function completed successfully.\r
+ Error value from LocatePpi()\r
+ Error Value from VariableServices->GetVariable()\r
+\r
+**/\r
+EFI_STATUS\r
+InstallS3Memory (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariableServices,\r
+ IN UINT32 TotalMemorySize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN S3MemoryBase;\r
+ UINTN S3MemorySize;\r
+ UINT8 SmramRanges;\r
+ UINT8 NumRanges;\r
+ UINT8 Index;\r
+ UINT8 SmramIndex;\r
+ UINTN BufferSize;\r
+ EFI_PEI_HOB_POINTERS Hob;\r
+ EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *SmramHobDescriptorBlock;\r
+ PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE MemoryMap[MAX_RANGES];\r
+ RESERVED_ACPI_S3_RANGE *S3MemoryRangeData;\r
+ EFI_SMRAM_DESCRIPTOR DescriptorAcpiVariable;\r
+\r
+ //\r
+ // Get the Memory Map\r
+ //\r
+ NumRanges = MAX_RANGES;\r
+\r
+ ZeroMem (MemoryMap, sizeof (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE) * NumRanges);\r
+\r
+ Status = GetMemoryMap (\r
+ PeiServices,\r
+ TotalMemorySize,\r
+ (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE *) MemoryMap,\r
+ &NumRanges\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Install physical memory descriptor hobs for each memory range.\r
+ //\r
+ SmramRanges = 0;\r
+ for (Index = 0; Index < NumRanges; Index++) {\r
+ if ((MemoryMap[Index].Type == DualChannelDdrSmramCacheable) ||\r
+ (MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable)) {\r
+ SmramRanges++;\r
+ }\r
+ }\r
+\r
+ ASSERT (SmramRanges > 0);\r
+\r
+ //\r
+ // Allocate one extra EFI_SMRAM_DESCRIPTOR to describe a page of SMRAM memory that contains a pointer\r
+ // to the SMM Services Table that is required on the S3 resume path\r
+ //\r
+ BufferSize = sizeof (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK);\r
+ if (SmramRanges > 0) {\r
+ BufferSize += ((SmramRanges - 1) * sizeof (EFI_SMRAM_DESCRIPTOR));\r
+ }\r
+\r
+ Hob.Raw = BuildGuidHob (\r
+ &gEfiSmmPeiSmramMemoryReserveGuid,\r
+ BufferSize\r
+ );\r
+ ASSERT (Hob.Raw);\r
+\r
+ SmramHobDescriptorBlock = (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *) (Hob.Raw);\r
+ SmramHobDescriptorBlock->NumberOfSmmReservedRegions = SmramRanges;\r
+\r
+ SmramIndex = 0;\r
+ for (Index = 0; Index < NumRanges; Index++) {\r
+ if ((MemoryMap[Index].Type == DualChannelDdrSmramCacheable) ||\r
+ (MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable)\r
+ ) {\r
+ //\r
+ // This is an SMRAM range, create an SMRAM descriptor\r
+ //\r
+ SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalStart = MemoryMap[Index].PhysicalAddress;\r
+ SmramHobDescriptorBlock->Descriptor[SmramIndex].CpuStart = MemoryMap[Index].CpuAddress;\r
+ SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalSize = MemoryMap[Index].RangeLength;\r
+ if (MemoryMap[Index].Type == DualChannelDdrSmramCacheable) {\r
+ SmramHobDescriptorBlock->Descriptor[SmramIndex].RegionState = EFI_SMRAM_CLOSED | EFI_CACHEABLE;\r
+ } else {\r
+ SmramHobDescriptorBlock->Descriptor[SmramIndex].RegionState = EFI_SMRAM_CLOSED;\r
+ }\r
+\r
+ SmramIndex++;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Build a HOB with the location of the reserved memory range.\r
+ //\r
+ CopyMem(&DescriptorAcpiVariable, &SmramHobDescriptorBlock->Descriptor[SmramRanges-1], sizeof(EFI_SMRAM_DESCRIPTOR));\r
+ DescriptorAcpiVariable.CpuStart += RESERVED_CPU_S3_SAVE_OFFSET;\r
+ BuildGuidDataHob (\r
+ &gEfiAcpiVariableGuid,\r
+ &DescriptorAcpiVariable,\r
+ sizeof (EFI_SMRAM_DESCRIPTOR)\r
+ );\r
+\r
+ //\r
+ // Get the location and size of the S3 memory range in the reserved page and\r
+ // install it as PEI Memory.\r
+ //\r
+\r
+ DEBUG ((EFI_D_INFO, "TSEG Base = 0x%08x\n", SmramHobDescriptorBlock->Descriptor[SmramRanges-1].PhysicalStart));\r
+ S3MemoryRangeData = (RESERVED_ACPI_S3_RANGE*)(UINTN)\r
+ (SmramHobDescriptorBlock->Descriptor[SmramRanges-1].PhysicalStart + RESERVED_ACPI_S3_RANGE_OFFSET);\r
+\r
+ S3MemoryBase = (UINTN) (S3MemoryRangeData->AcpiReservedMemoryBase);\r
+ DEBUG ((EFI_D_INFO, "S3MemoryBase = 0x%08x\n", S3MemoryBase));\r
+ S3MemorySize = (UINTN) (S3MemoryRangeData->AcpiReservedMemorySize);\r
+ DEBUG ((EFI_D_INFO, "S3MemorySize = 0x%08x\n", S3MemorySize));\r
+\r
+ Status = PeiServicesInstallPeiMemory (S3MemoryBase, S3MemorySize);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Retrieve the system memory length and build memory hob for the system\r
+ // memory above 1MB. So Memory Callback can set cache for the system memory\r
+ // correctly on S3 boot path, just like it does on Normal boot path.\r
+ //\r
+ ASSERT_EFI_ERROR ((S3MemoryRangeData->SystemMemoryLength - 0x100000) > 0);\r
+ BuildResourceDescriptorHob (\r
+ EFI_RESOURCE_SYSTEM_MEMORY,\r
+ (\r
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
+ EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |\r
+ EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
+ EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE\r
+ ),\r
+ 0x100000,\r
+ S3MemoryRangeData->SystemMemoryLength - 0x100000\r
+ );\r
+\r
+ for (Index = 0; Index < NumRanges; Index++) {\r
+ if ((MemoryMap[Index].Type == DualChannelDdrMainMemory) &&\r
+ (MemoryMap[Index].PhysicalAddress + MemoryMap[Index].RangeLength < 0x100000)) {\r
+ BuildResourceDescriptorHob (\r
+ EFI_RESOURCE_SYSTEM_MEMORY,\r
+ (\r
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
+ EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |\r
+ EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
+ EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE\r
+ ),\r
+ MemoryMap[Index].PhysicalAddress,\r
+ MemoryMap[Index].RangeLength\r
+ );\r
+ DEBUG ((EFI_D_INFO, "Build resource HOB for Legacy Region on S3 patch :"));\r
+ DEBUG ((EFI_D_INFO, " Memory Base:0x%lX Length:0x%lX\n", MemoryMap[Index].PhysicalAddress, MemoryMap[Index].RangeLength));\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+ This function returns the size, in bytes, required for the DXE phase.\r
+\r
+ @param PeiServices PEI Services table.\r
+ @param Size Pointer to the size, in bytes, required for the DXE phase.\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+RetriveRequiredMemorySize (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ OUT UINTN *Size\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PEI_HOB_POINTERS Hob;\r
+ EFI_MEMORY_TYPE_INFORMATION *MemoryData;\r
+ UINT8 Index;\r
+ UINTN TempPageNum;\r
+\r
+ MemoryData = NULL;\r
+ TempPageNum = 0;\r
+ Index = 0;\r
+\r
+ Status = PeiServicesGetHobList ((VOID **)&Hob.Raw);\r
+ while (!END_OF_HOB_LIST (Hob)) {\r
+ if (Hob.Header->HobType == EFI_HOB_TYPE_GUID_EXTENSION &&\r
+ CompareGuid (&Hob.Guid->Name, &gEfiMemoryTypeInformationGuid)\r
+ ) {\r
+ MemoryData = (EFI_MEMORY_TYPE_INFORMATION *) (Hob.Raw + sizeof (EFI_HOB_GENERIC_HEADER) + sizeof (EFI_GUID));\r
+ break;\r
+ }\r
+\r
+ Hob.Raw = GET_NEXT_HOB (Hob);\r
+ }\r
+ //\r
+ // Platform PEIM should supply such a information. Generic PEIM doesn't assume any default value\r
+ //\r
+ if (!MemoryData) {\r
+ return ;\r
+ }\r
+\r
+ while (MemoryData[Index].Type != EfiMaxMemoryType) {\r
+ //\r
+ // Accumulate default memory size requirements\r
+ //\r
+ TempPageNum += MemoryData[Index].NumberOfPages;\r
+ Index++;\r
+ }\r
+\r
+ if (TempPageNum == 0) {\r
+ return ;\r
+ }\r
+\r
+ //\r
+ // Add additional pages used by DXE memory manager\r
+ //\r
+ (*Size) = (TempPageNum + EDKII_DXE_MEM_SIZE_PAGES) * EFI_PAGE_SIZE;\r
+\r
+ return ;\r
+}\r
+\r
+/**\r
+\r
+ This function returns the memory ranges to be enabled, along with information\r
+ describing how the range should be used.\r
+\r
+ @param PeiServices PEI Services Table.\r
+ @param TimingData Detected DDR timing parameters for installed memory.\r
+ @param RowConfArray Pointer to an array of EFI_DUAL_CHANNEL_DDR_ROW_CONFIG structures. The number\r
+ of items in the array must match MaxRows returned by the McGetRowInfo() function.\r
+ @param MemoryMap Buffer to record details of the memory ranges tobe enabled.\r
+ @param NumRanges On input, this contains the maximum number of memory ranges that can be described\r
+ in the MemoryMap buffer.\r
+\r
+ @return MemoryMap The buffer will be filled in\r
+ NumRanges will contain the actual number of memory ranges that are to be anabled.\r
+ EFI_SUCCESS The function completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+GetMemoryMap (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN UINT32 TotalMemorySize,\r
+ IN OUT PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE *MemoryMap,\r
+ IN OUT UINT8 *NumRanges\r
+ )\r
+{\r
+ EFI_PHYSICAL_ADDRESS MemorySize;\r
+ EFI_PHYSICAL_ADDRESS RowLength;\r
+ EFI_STATUS Status;\r
+ PEI_MEMORY_RANGE_PCI_MEMORY PciMemoryMask;\r
+ PEI_MEMORY_RANGE_OPTION_ROM OptionRomMask;\r
+ PEI_MEMORY_RANGE_SMRAM SmramMask;\r
+ PEI_MEMORY_RANGE_SMRAM TsegMask;\r
+ UINT32 BlockNum;\r
+ UINT8 EsmramcRegister;\r
+ UINT8 ExtendedMemoryIndex;\r
+ UINT32 Register;\r
+\r
+ if ((*NumRanges) < MAX_RANGES) {\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ *NumRanges = 0;\r
+\r
+ //\r
+ // Find out which memory ranges to reserve on this platform\r
+ //\r
+ Status = ChooseRanges (\r
+ &OptionRomMask,\r
+ &SmramMask,\r
+ &PciMemoryMask\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Generate Memory ranges for the memory map.\r
+ //\r
+ EsmramcRegister = 0;\r
+ MemorySize = 0;\r
+\r
+ RowLength = TotalMemorySize;\r
+\r
+ //\r
+ // Add memory below 640KB to the memory map. Make sure memory between\r
+ // 640KB and 1MB are reserved, even if not used for SMRAM\r
+ //\r
+ MemoryMap[*NumRanges].PhysicalAddress = MemorySize;\r
+ MemoryMap[*NumRanges].CpuAddress = MemorySize;\r
+ MemoryMap[*NumRanges].RangeLength = 0xA0000;\r
+ MemoryMap[*NumRanges].Type = DualChannelDdrMainMemory;\r
+ (*NumRanges)++;\r
+\r
+ //\r
+ // Just mark this range reserved\r
+ //\r
+ MemoryMap[*NumRanges].PhysicalAddress = 0xA0000;\r
+ MemoryMap[*NumRanges].CpuAddress = 0xA0000;\r
+ MemoryMap[*NumRanges].RangeLength = 0x60000;\r
+ MemoryMap[*NumRanges].Type = DualChannelDdrReservedMemory;\r
+ (*NumRanges)++;\r
+\r
+ RowLength -= (0x100000 - MemorySize);\r
+ MemorySize = 0x100000;\r
+\r
+ //\r
+ // Add remaining memory to the memory map\r
+ //\r
+ MemoryMap[*NumRanges].PhysicalAddress = MemorySize;\r
+ MemoryMap[*NumRanges].CpuAddress = MemorySize;\r
+ MemoryMap[*NumRanges].RangeLength = RowLength;\r
+ MemoryMap[*NumRanges].Type = DualChannelDdrMainMemory;\r
+ (*NumRanges)++;\r
+ MemorySize += RowLength;\r
+\r
+ ExtendedMemoryIndex = (UINT8) (*NumRanges - 1);\r
+\r
+ // See if we need to trim TSEG out of the highest memory range\r
+ //\r
+ if (SmramMask & PEI_MR_SMRAM_TSEG_MASK) {//pcd\r
+ //\r
+ // Create the new range for TSEG and remove that range from the previous SdrDdrMainMemory range\r
+ //\r
+ TsegMask = (SmramMask & PEI_MR_SMRAM_SIZE_MASK);\r
+\r
+ BlockNum = 1;\r
+ while (TsegMask) {\r
+ TsegMask >>= 1;\r
+ BlockNum <<= 1;\r
+ }\r
+\r
+ BlockNum >>= 1;\r
+\r
+ if (BlockNum) {\r
+\r
+ MemoryMap[*NumRanges].RangeLength = (BlockNum * 128 * 1024);\r
+ Register = (UINT32)((MemorySize - 1) & SMM_END_MASK);\r
+ MemorySize -= MemoryMap[*NumRanges].RangeLength;\r
+ MemoryMap[*NumRanges].PhysicalAddress = MemorySize;\r
+ MemoryMap[*NumRanges].CpuAddress = MemorySize;\r
+ MemoryMap[ExtendedMemoryIndex].RangeLength -= MemoryMap[*NumRanges].RangeLength;\r
+\r
+ //\r
+ // Update QuarkNcSoc HSMMCTL register\r
+ //\r
+ Register |= (UINT32)(((RShiftU64(MemorySize, 16)) & SMM_START_MASK) + (SMM_WRITE_OPEN | SMM_READ_OPEN | SMM_CODE_RD_OPEN));\r
+ QncHsmmcWrite (Register);\r
+ }\r
+\r
+ //\r
+ // Chipset only supports cacheable SMRAM\r
+ //\r
+ MemoryMap[*NumRanges].Type = DualChannelDdrSmramCacheable;\r
+\r
+ (*NumRanges)++;\r
+ }\r
+\r
+ //\r
+ // trim 64K memory from highest memory range for Rmu Main binary shadow\r
+ //\r
+ MemoryMap[*NumRanges].RangeLength = 0x10000;\r
+ MemorySize -= MemoryMap[*NumRanges].RangeLength;\r
+ MemoryMap[*NumRanges].PhysicalAddress = MemorySize;\r
+ MemoryMap[*NumRanges].CpuAddress = MemorySize;\r
+ MemoryMap[ExtendedMemoryIndex].RangeLength -= MemoryMap[*NumRanges].RangeLength;\r
+ MemoryMap[*NumRanges].Type = DualChannelDdrReservedMemory;\r
+ (*NumRanges)++;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+Routine Description:\r
+\r
+ Fill in bit masks to specify reserved memory ranges on the Lakeport platform\r
+\r
+Arguments:\r
+\r
+Returns:\r
+\r
+ OptionRomMask - Bit mask specifying memory regions reserved for Legacy option\r
+ ROM use (if any)\r
+\r
+ SmramMask - Bit mask specifying memory regions reserved for SMM use (if any)\r
+\r
+**/\r
+EFI_STATUS\r
+ChooseRanges (\r
+ IN OUT PEI_MEMORY_RANGE_OPTION_ROM *OptionRomMask,\r
+ IN OUT PEI_MEMORY_RANGE_SMRAM *SmramMask,\r
+ IN OUT PEI_MEMORY_RANGE_PCI_MEMORY *PciMemoryMask\r
+ )\r
+{\r
+\r
+ //\r
+ // Choose regions to reserve for Option ROM use\r
+ //\r
+ *OptionRomMask = PEI_MR_OPTION_ROM_NONE;\r
+\r
+ //\r
+ // Choose regions to reserve for SMM use (AB/H SEG and TSEG). Size is in 128K blocks\r
+ //\r
+ *SmramMask = PEI_MR_SMRAM_CACHEABLE_MASK | PEI_MR_SMRAM_TSEG_MASK | ((PcdGet32(PcdTSegSize)) >> 17);\r
+\r
+ *PciMemoryMask = 0;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+GetPlatformMemorySize (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_BOOT_MODE BootMode,\r
+ IN OUT UINT64 *MemorySize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PEI_READ_ONLY_VARIABLE2_PPI *Variable;\r
+ UINTN DataSize;\r
+ EFI_MEMORY_TYPE_INFORMATION MemoryData [EfiMaxMemoryType + 1];\r
+ UINTN Index;\r
+\r
+ DataSize = sizeof (MemoryData);\r
+\r
+ if (BootMode == BOOT_IN_RECOVERY_MODE) {\r
+\r
+ //\r
+ // // Treat recovery as if variable not found (eg 1st boot).\r
+ //\r
+ Status = EFI_NOT_FOUND;\r
+\r
+ } else {\r
+ Status = PeiServicesLocatePpi (\r
+ &gEfiPeiReadOnlyVariable2PpiGuid,\r
+ 0,\r
+ NULL,\r
+ (VOID **)&Variable\r
+ );\r
+\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ DataSize = sizeof (MemoryData);\r
+ Status = Variable->GetVariable (\r
+ Variable,\r
+ EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,\r
+ &gEfiMemoryTypeInformationGuid,\r
+ NULL,\r
+ &DataSize,\r
+ &MemoryData\r
+ );\r
+ }\r
+\r
+ //\r
+ // Accumulate maximum amount of memory needed\r
+ //\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Start with minimum memory\r
+ //\r
+ *MemorySize = PEI_MIN_MEMORY_SIZE;\r
+\r
+ for (Index = 0; Index < sizeof(mDefaultQncMemoryTypeInformation) / sizeof (EFI_MEMORY_TYPE_INFORMATION); Index++) {\r
+ *MemorySize += mDefaultQncMemoryTypeInformation[Index].NumberOfPages * EFI_PAGE_SIZE;\r
+ }\r
+\r
+ //\r
+ // Build the GUID'd HOB for DXE\r
+ //\r
+ BuildGuidDataHob (\r
+ &gEfiMemoryTypeInformationGuid,\r
+ mDefaultQncMemoryTypeInformation,\r
+ sizeof(mDefaultQncMemoryTypeInformation)\r
+ );\r
+ } else {\r
+ //\r
+ // Start with at least PEI_MIN_MEMORY_SIZE pages of memory for the DXE Core and the DXE Stack\r
+ //\r
+\r
+ *MemorySize = PEI_MIN_MEMORY_SIZE;\r
+ for (Index = 0; Index < DataSize / sizeof (EFI_MEMORY_TYPE_INFORMATION); Index++) {\r
+ DEBUG ((EFI_D_INFO, "Index %d, Page: %d\n", Index, MemoryData[Index].NumberOfPages));\r
+ *MemorySize += MemoryData[Index].NumberOfPages * EFI_PAGE_SIZE;\r
+ }\r
+\r
+ //\r
+ // Build the GUID'd HOB for DXE\r
+ //\r
+ BuildGuidDataHob (\r
+ &gEfiMemoryTypeInformationGuid,\r
+ MemoryData,\r
+ DataSize\r
+ );\r
+\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+BaseMemoryTest (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PHYSICAL_ADDRESS BeginAddress,\r
+ IN UINT64 MemoryLength,\r
+ IN PEI_MEMORY_TEST_OP Operation,\r
+ OUT EFI_PHYSICAL_ADDRESS *ErrorAddress\r
+ )\r
+{\r
+ UINT32 TestPattern;\r
+ EFI_PHYSICAL_ADDRESS TempAddress;\r
+ UINT32 SpanSize;\r
+\r
+ TestPattern = 0x5A5A5A5A;\r
+ SpanSize = 0;\r
+\r
+ //\r
+ // Make sure we don't try and test anything above the max physical address range\r
+ //\r
+ ASSERT (BeginAddress + MemoryLength < MAX_ADDRESS);\r
+\r
+ switch (Operation) {\r
+ case Extensive:\r
+ SpanSize = 0x4;\r
+ break;\r
+\r
+ case Sparse:\r
+ case Quick:\r
+ SpanSize = 0x40000;\r
+ break;\r
+\r
+ case Ignore:\r
+ goto Done;\r
+ break;\r
+ }\r
+ //\r
+ // Write the test pattern into memory range\r
+ //\r
+ TempAddress = BeginAddress;\r
+ while (TempAddress < BeginAddress + MemoryLength) {\r
+ (*(UINT32 *) (UINTN) TempAddress) = TestPattern;\r
+ TempAddress += SpanSize;\r
+ }\r
+ //\r
+ // Read pattern from memory and compare it\r
+ //\r
+ TempAddress = BeginAddress;\r
+ while (TempAddress < BeginAddress + MemoryLength) {\r
+ if ((*(UINT32 *) (UINTN) TempAddress) != TestPattern) {\r
+ *ErrorAddress = TempAddress;\r
+ DEBUG ((EFI_D_ERROR, "Memory test failed at 0x%x.\n", TempAddress));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ TempAddress += SpanSize;\r
+ }\r
+\r
+Done:\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+ This function sets up the platform specific IMR protection for the various\r
+ memory regions.\r
+\r
+ @param PeiMemoryBaseAddress Base address of memory allocated for PEI.\r
+ @param PeiMemoryLength Length in bytes of the PEI memory (includes ACPI memory).\r
+ @param RequiredMemSize Size in bytes of the ACPI/Runtime memory\r
+\r
+ @return EFI_SUCCESS The function completed successfully.\r
+ EFI_ACCESS_DENIED Access to IMRs failed.\r
+\r
+**/\r
+EFI_STATUS\r
+SetPlatformImrPolicy (\r
+ IN EFI_PHYSICAL_ADDRESS PeiMemoryBaseAddress,\r
+ IN UINT64 PeiMemoryLength,\r
+ IN UINTN RequiredMemSize\r
+ )\r
+{\r
+ UINT8 Index;\r
+ UINT32 Register;\r
+ UINT16 DeviceId;\r
+\r
+ //\r
+ // Check what Soc we are running on (read Host bridge DeviceId)\r
+ //\r
+ DeviceId = QNCMmPci16(0, MC_BUS, MC_DEV, MC_FUN, PCI_DEVICE_ID_OFFSET);\r
+\r
+ //\r
+ // If any IMR register is locked then we cannot proceed\r
+ //\r
+ 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
+ {\r
+ Register = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, Index);\r
+ if (Register & IMR_LOCK) {\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Add IMR0 protection for the 'PeiMemory'\r
+ //\r
+ QncImrWrite (\r
+ QUARK_NC_MEMORY_MANAGER_IMR0,\r
+ (UINT32)(((RShiftU64(PeiMemoryBaseAddress, 8)) & IMRL_MASK) | IMR_EN),\r
+ (UINT32)((RShiftU64((PeiMemoryBaseAddress+PeiMemoryLength-RequiredMemSize + EFI_PAGES_TO_SIZE(EDKII_DXE_MEM_SIZE_PAGES-1) - 1), 8)) & IMRL_MASK),\r
+ (UINT32)(CPU_SNOOP + CPU0_NON_SMM),\r
+ (UINT32)(CPU_SNOOP + CPU0_NON_SMM)\r
+ );\r
+\r
+ //\r
+ // Add IMR2 protection for shadowed RMU binary.\r
+ //\r
+ QncImrWrite (\r
+ QUARK_NC_MEMORY_MANAGER_IMR2,\r
+ (UINT32)(((RShiftU64((PeiMemoryBaseAddress+PeiMemoryLength), 8)) & IMRH_MASK) | IMR_EN),\r
+ (UINT32)((RShiftU64((PeiMemoryBaseAddress+PeiMemoryLength+PcdGet32(PcdFlashQNCMicrocodeSize)-1), 8)) & IMRH_MASK),\r
+ (UINT32)(CPU_SNOOP + RMU + CPU0_NON_SMM),\r
+ (UINT32)(CPU_SNOOP + RMU + CPU0_NON_SMM)\r
+ );\r
+\r
+ //\r
+ // Add IMR3 protection for the default SMRAM.\r
+ //\r
+ QncImrWrite (\r
+ QUARK_NC_MEMORY_MANAGER_IMR3,\r
+ (UINT32)(((RShiftU64((SMM_DEFAULT_SMBASE), 8)) & IMRL_MASK) | IMR_EN),\r
+ (UINT32)((RShiftU64((SMM_DEFAULT_SMBASE+SMM_DEFAULT_SMBASE_SIZE_BYTES-1), 8)) & IMRH_MASK),\r
+ (UINT32)(CPU_SNOOP + CPU0_NON_SMM),\r
+ (UINT32)(CPU_SNOOP + CPU0_NON_SMM)\r
+ );\r
+\r
+ //\r
+ // Add IMR5 protection for the legacy S3 and AP Startup Vector region (below 1MB).\r
+ //\r
+ QncImrWrite (\r
+ QUARK_NC_MEMORY_MANAGER_IMR5,\r
+ (UINT32)(((RShiftU64(AP_STARTUP_VECTOR, 8)) & IMRL_MASK) | IMR_EN),\r
+ (UINT32)((RShiftU64((AP_STARTUP_VECTOR + EFI_PAGE_SIZE - 1), 8)) & IMRH_MASK),\r
+ (UINT32)(CPU_SNOOP + CPU0_NON_SMM),\r
+ (UINT32)(CPU_SNOOP + CPU0_NON_SMM)\r
+ );\r
+\r
+ //\r
+ // Add IMR6 protection for the ACPI Reclaim/ACPI/Runtime Services.\r
+ //\r
+ QncImrWrite (\r
+ QUARK_NC_MEMORY_MANAGER_IMR6,\r
+ (UINT32)(((RShiftU64((PeiMemoryBaseAddress+PeiMemoryLength-RequiredMemSize+EFI_PAGES_TO_SIZE(EDKII_DXE_MEM_SIZE_PAGES-1)), 8)) & IMRL_MASK) | IMR_EN),\r
+ (UINT32)((RShiftU64((PeiMemoryBaseAddress+PeiMemoryLength-EFI_PAGE_SIZE-1), 8)) & IMRH_MASK),\r
+ (UINT32)(CPU_SNOOP + CPU0_NON_SMM),\r
+ (UINT32)(CPU_SNOOP + CPU0_NON_SMM)\r
+ );\r
+\r
+ //\r
+ // Enable IMR4 protection of eSRAM.\r
+ //\r
+ QncImrWrite (\r
+ QUARK_NC_MEMORY_MANAGER_IMR4,\r
+ (UINT32)(((RShiftU64((UINTN)PcdGet32 (PcdEsramStage1Base), 8)) & IMRL_MASK) | IMR_EN),\r
+ (UINT32)((RShiftU64(((UINTN)PcdGet32 (PcdEsramStage1Base) + (UINTN)PcdGet32 (PcdESramMemorySize) - 1), 8)) & IMRH_MASK),\r
+ (UINT32)(CPU_SNOOP + CPU0_NON_SMM),\r
+ (UINT32)(CPU_SNOOP + CPU0_NON_SMM)\r
+ );\r
+\r
+ //\r
+ // Enable Interrupt on IMR/SMM Violation\r
+ //\r
+ QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_BIMRVCTL, (UINT32)(EnableIMRInt));\r
+ if (DeviceId == QUARK2_MC_DEVICE_ID) {\r
+ QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_BSMMVCTL, (UINT32)(EnableSMMInt));\r
+ }\r
+\r
+ //\r
+ // Disable IMR7 memory protection (eSRAM + DDR3 memory) since our policies\r
+ // are now setup.\r
+ //\r
+ QncImrWrite (\r
+ QUARK_NC_MEMORY_MANAGER_IMR7,\r
+ (UINT32)(IMRL_RESET & ~IMR_EN),\r
+ (UINT32)IMRH_RESET,\r
+ (UINT32)IMRX_ALL_ACCESS,\r
+ (UINT32)IMRX_ALL_ACCESS\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** Return info derived from Installing Memory by MemoryInit.\r
+\r
+ @param[out] RmuMainBaseAddressPtr Return RmuMainBaseAddress to this location.\r
+ @param[out] SmramDescriptorPtr Return start of Smram descriptor list to this location.\r
+ @param[out] NumSmramRegionsPtr Return numbers of Smram regions to this location.\r
+\r
+ @return Address of RMU shadow region at the top of available memory.\r
+ @return List of Smram descriptors for each Smram region.\r
+ @return Numbers of Smram regions.\r
+**/\r
+VOID\r
+EFIAPI\r
+InfoPostInstallMemory (\r
+ OUT UINT32 *RmuMainBaseAddressPtr OPTIONAL,\r
+ OUT EFI_SMRAM_DESCRIPTOR **SmramDescriptorPtr OPTIONAL,\r
+ OUT UINTN *NumSmramRegionsPtr OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PEI_HOB_POINTERS Hob;\r
+ UINT64 CalcLength;\r
+ EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *SmramHobDescriptorBlock;\r
+\r
+ if ((RmuMainBaseAddressPtr == NULL) && (SmramDescriptorPtr == NULL) && (NumSmramRegionsPtr == NULL)) {\r
+ return;\r
+ }\r
+\r
+ SmramHobDescriptorBlock = NULL;\r
+ if (SmramDescriptorPtr != NULL) {\r
+ *SmramDescriptorPtr = NULL;\r
+ }\r
+ if (NumSmramRegionsPtr != NULL) {\r
+ *NumSmramRegionsPtr = 0;\r
+ }\r
+\r
+ //\r
+ // Calculate RMU shadow region base address.\r
+ // Set to 1 MB. Since 1MB cacheability will always be set\r
+ // until override by CSM.\r
+ //\r
+ CalcLength = 0x100000;\r
+\r
+ Status = PeiServicesGetHobList ((VOID **) &Hob.Raw);\r
+ ASSERT_EFI_ERROR (Status);\r
+ while (!END_OF_HOB_LIST (Hob)) {\r
+ if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
+ if (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {\r
+ //\r
+ // Skip the memory region below 1MB\r
+ //\r
+ if (Hob.ResourceDescriptor->PhysicalStart >= 0x100000) {\r
+ CalcLength += (UINT64) (Hob.ResourceDescriptor->ResourceLength);\r
+ }\r
+ }\r
+ } else if (Hob.Header->HobType == EFI_HOB_TYPE_GUID_EXTENSION) {\r
+ if (CompareGuid (&(Hob.Guid->Name), &gEfiSmmPeiSmramMemoryReserveGuid)) {\r
+ SmramHobDescriptorBlock = (VOID*) (Hob.Raw + sizeof (EFI_HOB_GUID_TYPE));\r
+ if (SmramDescriptorPtr != NULL) {\r
+ *SmramDescriptorPtr = SmramHobDescriptorBlock->Descriptor;\r
+ }\r
+ if (NumSmramRegionsPtr != NULL) {\r
+ *NumSmramRegionsPtr = SmramHobDescriptorBlock->NumberOfSmmReservedRegions;\r
+ }\r
+ }\r
+ }\r
+ Hob.Raw = GET_NEXT_HOB (Hob);\r
+ }\r
+\r
+ if (RmuMainBaseAddressPtr != NULL) {\r
+ *RmuMainBaseAddressPtr = (UINT32) CalcLength;\r
+ }\r
+}\r