Home | History | Annotate | Download | only in PlatformInit
      1 /** @file
      2 Framework PEIM to initialize memory on a Quark Memory Controller.
      3 
      4 Copyright (c) 2013 - 2016, 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
     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
     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
    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
    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
    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
    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
    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
    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
    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   EFI_RESOURCE_ATTRIBUTE_TYPE           Attribute;
    558   EFI_PHYSICAL_ADDRESS                  BadMemoryAddress;
    559   EFI_SMRAM_DESCRIPTOR                  DescriptorAcpiVariable;
    560   VOID                                  *CapsuleBuffer;
    561   UINTN                                 CapsuleBufferLength;
    562   PEI_CAPSULE_PPI                       *Capsule;
    563   VOID                                  *LargeMemRangeBuf;
    564   UINTN                                 LargeMemRangeBufLen;
    565   UINT8                                 MorControl;
    566   UINTN                                 DataSize;
    567 
    568   //
    569   // Test the memory from 1M->TOM
    570   //
    571   if (BootMode != BOOT_ON_FLASH_UPDATE) {
    572     Status = BaseMemoryTest (
    573               PeiServices,
    574               0x100000,
    575               (TotalMemorySize - 0x100000),
    576               Quick,
    577               &BadMemoryAddress
    578               );
    579   ASSERT_EFI_ERROR (Status);
    580   }
    581 
    582 
    583   //
    584   // Get the Memory Map
    585   //
    586   NumRanges = MAX_RANGES;
    587 
    588   ZeroMem (MemoryMap, sizeof (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE) * NumRanges);
    589 
    590   Status = GetMemoryMap (
    591              PeiServices,
    592              TotalMemorySize,
    593              (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE *) MemoryMap,
    594              &NumRanges
    595              );
    596   ASSERT_EFI_ERROR (Status);
    597 
    598   //
    599   // Find the highest memory range in processor native address space to give to
    600   // PEI. Then take the top.
    601   //
    602   PeiMemoryBaseAddress = 0;
    603 
    604   //
    605   // Query the platform for the minimum memory size
    606   //
    607 
    608   Status = GetPlatformMemorySize (
    609              PeiServices,
    610              BootMode,
    611              &PeiMemoryLength
    612              );
    613   ASSERT_EFI_ERROR (Status);
    614 
    615   //
    616   // Detect MOR request by the OS.
    617   //
    618   MorControl = 0;
    619   DataSize = sizeof (MorControl);
    620   Status = VariableServices->GetVariable (
    621                                VariableServices,
    622                                MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
    623                                &gEfiMemoryOverwriteControlDataGuid,
    624                                NULL,
    625                                &DataSize,
    626                                &MorControl
    627                                );
    628 
    629   PeiMemoryIndex = 0;
    630 
    631   for (Index = 0; Index < NumRanges; Index++)
    632   {
    633     DEBUG ((EFI_D_INFO, "Found 0x%x bytes at ", MemoryMap[Index].RangeLength));
    634     DEBUG ((EFI_D_INFO, "0x%x.\n", MemoryMap[Index].PhysicalAddress));
    635 
    636     //
    637     // If OS requested a memory overwrite perform it now.  Only do it for memory
    638     // used by the OS.
    639     //
    640     if (MOR_CLEAR_MEMORY_VALUE (MorControl) && MemoryMap[Index].Type == DualChannelDdrMainMemory) {
    641       DEBUG ((EFI_D_INFO, "Clear memory per MOR request.\n"));
    642       if ((UINTN)MemoryMap[Index].RangeLength > 0) {
    643         if ((UINTN)MemoryMap[Index].PhysicalAddress == 0) {
    644           //
    645           // ZeroMem() generates an ASSERT() if Buffer parameter is NULL.
    646           // Clear byte at 0 and start clear operation at address 1.
    647           //
    648           *(UINT8 *)(0) = 0;
    649           ZeroMem ((VOID *)1, (UINTN)MemoryMap[Index].RangeLength - 1);
    650         } else {
    651           ZeroMem (
    652             (VOID *)(UINTN)MemoryMap[Index].PhysicalAddress,
    653             (UINTN)MemoryMap[Index].RangeLength
    654             );
    655         }
    656       }
    657     }
    658 
    659     if ((MemoryMap[Index].Type == DualChannelDdrMainMemory) &&
    660         (MemoryMap[Index].PhysicalAddress + MemoryMap[Index].RangeLength < MAX_ADDRESS) &&
    661         (MemoryMap[Index].PhysicalAddress >= PeiMemoryBaseAddress) &&
    662         (MemoryMap[Index].RangeLength >= PeiMemoryLength)) {
    663       PeiMemoryBaseAddress = MemoryMap[Index].PhysicalAddress +
    664                              MemoryMap[Index].RangeLength -
    665                              PeiMemoryLength;
    666       PeiMemoryIndex = Index;
    667     }
    668   }
    669 
    670   //
    671   // Find the largest memory range excluding that given to PEI.
    672   //
    673   LargeMemRangeBuf = NULL;
    674   LargeMemRangeBufLen = 0;
    675   for (Index = 0; Index < NumRanges; Index++) {
    676     if ((MemoryMap[Index].Type == DualChannelDdrMainMemory) &&
    677         (MemoryMap[Index].PhysicalAddress + MemoryMap[Index].RangeLength < MAX_ADDRESS)) {
    678           if (Index != PeiMemoryIndex) {
    679             if (MemoryMap[Index].RangeLength > LargeMemRangeBufLen) {
    680               LargeMemRangeBuf = (VOID *) ((UINTN) MemoryMap[Index].PhysicalAddress);
    681               LargeMemRangeBufLen = (UINTN) MemoryMap[Index].RangeLength;
    682             }
    683           } else {
    684             if ((MemoryMap[Index].RangeLength - PeiMemoryLength) >= LargeMemRangeBufLen) {
    685               LargeMemRangeBuf = (VOID *) ((UINTN) MemoryMap[Index].PhysicalAddress);
    686               LargeMemRangeBufLen = (UINTN) (MemoryMap[Index].RangeLength - PeiMemoryLength);
    687             }
    688           }
    689     }
    690   }
    691 
    692   Capsule             = NULL;
    693   CapsuleBuffer       = NULL;
    694   CapsuleBufferLength = 0;
    695   if (BootMode == BOOT_ON_FLASH_UPDATE) {
    696     Status = PeiServicesLocatePpi (
    697                &gPeiCapsulePpiGuid,  // GUID
    698                0,                    // INSTANCE
    699                NULL,                 // EFI_PEI_PPI_DESCRIPTOR
    700                (VOID **)&Capsule     // PPI
    701                );
    702     ASSERT_EFI_ERROR (Status);
    703 
    704     if (Status == EFI_SUCCESS) {
    705       CapsuleBuffer = LargeMemRangeBuf;
    706       CapsuleBufferLength = LargeMemRangeBufLen;
    707 
    708       //
    709       // Call the Capsule PPI Coalesce function to coalesce the capsule data.
    710       //
    711       Status = Capsule->Coalesce (
    712                           PeiServices,
    713                           &CapsuleBuffer,
    714                           &CapsuleBufferLength
    715                           );
    716       //
    717       // If it failed, then NULL out our capsule PPI pointer so that the capsule
    718       // HOB does not get created below.
    719       //
    720       if (Status != EFI_SUCCESS) {
    721         Capsule = NULL;
    722       }
    723     }
    724   }
    725 
    726   //
    727   // Set up the IMR policy required for this platform
    728   //
    729   Status = SetPlatformImrPolicy (
    730               PeiMemoryBaseAddress,
    731               PeiMemoryLength
    732               );
    733   ASSERT_EFI_ERROR (Status);
    734 
    735   //
    736   // Carve out the top memory reserved for ACPI
    737   //
    738   Status        = PeiServicesInstallPeiMemory (PeiMemoryBaseAddress, PeiMemoryLength);
    739   ASSERT_EFI_ERROR (Status);
    740 
    741   BuildResourceDescriptorHob (
    742    EFI_RESOURCE_SYSTEM_MEMORY,                       // MemoryType,
    743    (
    744    EFI_RESOURCE_ATTRIBUTE_PRESENT |
    745    EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
    746    EFI_RESOURCE_ATTRIBUTE_TESTED |
    747    EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
    748    EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
    749    EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
    750    EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
    751    ),
    752    PeiMemoryBaseAddress,                             // MemoryBegin
    753    PeiMemoryLength                                   // MemoryLength
    754    );
    755 
    756   //
    757   // Install physical memory descriptor hobs for each memory range.
    758   //
    759   SmramRanges = 0;
    760   for (Index = 0; Index < NumRanges; Index++) {
    761     Attribute = 0;
    762     if (MemoryMap[Index].Type == DualChannelDdrMainMemory)
    763     {
    764       if (Index == PeiMemoryIndex) {
    765         //
    766         // This is a partially tested Main Memory range, give it to EFI
    767         //
    768         BuildResourceDescriptorHob (
    769           EFI_RESOURCE_SYSTEM_MEMORY,
    770           (
    771           EFI_RESOURCE_ATTRIBUTE_PRESENT |
    772           EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
    773           EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
    774           EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
    775           EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
    776           EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
    777           ),
    778           MemoryMap[Index].PhysicalAddress,
    779           MemoryMap[Index].RangeLength - PeiMemoryLength
    780           );
    781       } else {
    782         //
    783         // This is an untested Main Memory range, give it to EFI
    784         //
    785         BuildResourceDescriptorHob (
    786           EFI_RESOURCE_SYSTEM_MEMORY,       // MemoryType,
    787           (
    788           EFI_RESOURCE_ATTRIBUTE_PRESENT |
    789           EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
    790           EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
    791           EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
    792           EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
    793           EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
    794           ),
    795           MemoryMap[Index].PhysicalAddress, // MemoryBegin
    796           MemoryMap[Index].RangeLength      // MemoryLength
    797           );
    798       }
    799     } else {
    800       if ((MemoryMap[Index].Type == DualChannelDdrSmramCacheable) ||
    801           (MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable)) {
    802         SmramRanges++;
    803       }
    804       if ((MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable) ||
    805           (MemoryMap[Index].Type == DualChannelDdrGraphicsMemoryNonCacheable)) {
    806         Attribute |= EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE;
    807       }
    808       if ((MemoryMap[Index].Type == DualChannelDdrSmramCacheable)         ||
    809           (MemoryMap[Index].Type == DualChannelDdrGraphicsMemoryCacheable)) {
    810         //
    811         // TSEG and HSEG can be used with a write-back(WB) cache policy; however,
    812         // the specification requires that the TSEG and HSEG space be cached only
    813         // inside of the SMI handler. when using HSEG or TSEG an IA-32 processor
    814         // does not automatically write back and invalidate its cache before entering
    815         // SMM or before existing SMM therefore any MTRR defined for the active TSEG
    816         // or HSEG must be set to un-cacheable(UC) outside of SMM.
    817         //
    818         Attribute |= EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE | EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE;
    819       }
    820       if (MemoryMap[Index].Type == DualChannelDdrReservedMemory) {
    821         Attribute |= EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
    822                      EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE;
    823       }
    824       //
    825       // Make sure non-system memory is marked as reserved
    826       //
    827       BuildResourceDescriptorHob (
    828         EFI_RESOURCE_MEMORY_RESERVED,     // MemoryType,
    829         Attribute,                        // MemoryAttribute
    830         MemoryMap[Index].PhysicalAddress, // MemoryBegin
    831         MemoryMap[Index].RangeLength      // MemoryLength
    832         );
    833     }
    834   }
    835 
    836   //
    837   // Allocate one extra EFI_SMRAM_DESCRIPTOR to describe a page of SMRAM memory that contains a pointer
    838   // to the SMM Services Table that is required on the S3 resume path
    839   //
    840   ASSERT (SmramRanges > 0);
    841   BufferSize = sizeof (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK);
    842   BufferSize += ((SmramRanges - 1) * sizeof (EFI_SMRAM_DESCRIPTOR));
    843 
    844   Hob.Raw = BuildGuidHob (
    845               &gEfiSmmPeiSmramMemoryReserveGuid,
    846               BufferSize
    847               );
    848   ASSERT (Hob.Raw);
    849 
    850   SmramHobDescriptorBlock = (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *) (Hob.Raw);
    851   SmramHobDescriptorBlock->NumberOfSmmReservedRegions = SmramRanges;
    852 
    853   SmramIndex = 0;
    854   for (Index = 0; Index < NumRanges; Index++) {
    855     if ((MemoryMap[Index].Type == DualChannelDdrSmramCacheable) ||
    856         (MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable)
    857         ) {
    858       //
    859       // This is an SMRAM range, create an SMRAM descriptor
    860       //
    861       SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalStart = MemoryMap[Index].PhysicalAddress;
    862       SmramHobDescriptorBlock->Descriptor[SmramIndex].CpuStart      = MemoryMap[Index].CpuAddress;
    863       SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalSize  = MemoryMap[Index].RangeLength;
    864       if (MemoryMap[Index].Type == DualChannelDdrSmramCacheable) {
    865         SmramHobDescriptorBlock->Descriptor[SmramIndex].RegionState = EFI_SMRAM_CLOSED | EFI_CACHEABLE;
    866       } else {
    867         SmramHobDescriptorBlock->Descriptor[SmramIndex].RegionState = EFI_SMRAM_CLOSED;
    868       }
    869 
    870       SmramIndex++;
    871     }
    872   }
    873 
    874   //
    875   // Build a HOB with the location of the reserved memory range.
    876   //
    877   CopyMem(&DescriptorAcpiVariable, &SmramHobDescriptorBlock->Descriptor[SmramRanges-1], sizeof(EFI_SMRAM_DESCRIPTOR));
    878   DescriptorAcpiVariable.CpuStart += RESERVED_CPU_S3_SAVE_OFFSET;
    879   BuildGuidDataHob (
    880     &gEfiAcpiVariableGuid,
    881     &DescriptorAcpiVariable,
    882     sizeof (EFI_SMRAM_DESCRIPTOR)
    883     );
    884 
    885   //
    886   // If we found the capsule PPI (and we didn't have errors), then
    887   // call the capsule PEIM to allocate memory for the capsule.
    888   //
    889   if (Capsule != NULL) {
    890     Status = Capsule->CreateState (PeiServices, CapsuleBuffer, CapsuleBufferLength);
    891   }
    892 
    893   return EFI_SUCCESS;
    894 }
    895 
    896 /**
    897 
    898   Find memory that is reserved so PEI has some to use.
    899 
    900   @param  PeiServices      PEI Services table.
    901   @param  VariableSevices  Variable PPI instance.
    902 
    903   @return EFI_SUCCESS  The function completed successfully.
    904                        Error value from LocatePpi()
    905                        Error Value from VariableServices->GetVariable()
    906 
    907 **/
    908 EFI_STATUS
    909 InstallS3Memory (
    910   IN      EFI_PEI_SERVICES                      **PeiServices,
    911   IN      EFI_PEI_READ_ONLY_VARIABLE2_PPI       *VariableServices,
    912   IN      UINT32                                TotalMemorySize
    913   )
    914 {
    915   EFI_STATUS                            Status;
    916   UINTN                                 S3MemoryBase;
    917   UINTN                                 S3MemorySize;
    918   UINT8                                 SmramRanges;
    919   UINT8                                 NumRanges;
    920   UINT8                                 Index;
    921   UINT8                                 SmramIndex;
    922   UINTN                                 BufferSize;
    923   EFI_PEI_HOB_POINTERS                  Hob;
    924   EFI_SMRAM_HOB_DESCRIPTOR_BLOCK        *SmramHobDescriptorBlock;
    925   PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE MemoryMap[MAX_RANGES];
    926   RESERVED_ACPI_S3_RANGE                *S3MemoryRangeData;
    927   EFI_SMRAM_DESCRIPTOR                  DescriptorAcpiVariable;
    928 
    929   //
    930   // Get the Memory Map
    931   //
    932   NumRanges = MAX_RANGES;
    933 
    934   ZeroMem (MemoryMap, sizeof (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE) * NumRanges);
    935 
    936   Status = GetMemoryMap (
    937              PeiServices,
    938              TotalMemorySize,
    939              (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE *) MemoryMap,
    940              &NumRanges
    941              );
    942   ASSERT_EFI_ERROR (Status);
    943 
    944   //
    945   // Install physical memory descriptor hobs for each memory range.
    946   //
    947   SmramRanges = 0;
    948   for (Index = 0; Index < NumRanges; Index++) {
    949     if ((MemoryMap[Index].Type == DualChannelDdrSmramCacheable)    ||
    950        (MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable)) {
    951       SmramRanges++;
    952     }
    953   }
    954 
    955   ASSERT (SmramRanges > 0);
    956 
    957   //
    958   // Allocate one extra EFI_SMRAM_DESCRIPTOR to describe a page of SMRAM memory that contains a pointer
    959   // to the SMM Services Table that is required on the S3 resume path
    960   //
    961   BufferSize = sizeof (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK);
    962   if (SmramRanges > 0) {
    963     BufferSize += ((SmramRanges - 1) * sizeof (EFI_SMRAM_DESCRIPTOR));
    964   }
    965 
    966   Hob.Raw = BuildGuidHob (
    967               &gEfiSmmPeiSmramMemoryReserveGuid,
    968               BufferSize
    969               );
    970   ASSERT (Hob.Raw);
    971 
    972   SmramHobDescriptorBlock = (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *) (Hob.Raw);
    973   SmramHobDescriptorBlock->NumberOfSmmReservedRegions = SmramRanges;
    974 
    975   SmramIndex = 0;
    976   for (Index = 0; Index < NumRanges; Index++) {
    977     if ((MemoryMap[Index].Type == DualChannelDdrSmramCacheable) ||
    978         (MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable)
    979         ) {
    980       //
    981       // This is an SMRAM range, create an SMRAM descriptor
    982       //
    983       SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalStart = MemoryMap[Index].PhysicalAddress;
    984       SmramHobDescriptorBlock->Descriptor[SmramIndex].CpuStart      = MemoryMap[Index].CpuAddress;
    985       SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalSize  = MemoryMap[Index].RangeLength;
    986       if (MemoryMap[Index].Type == DualChannelDdrSmramCacheable) {
    987         SmramHobDescriptorBlock->Descriptor[SmramIndex].RegionState = EFI_SMRAM_CLOSED | EFI_CACHEABLE;
    988       } else {
    989         SmramHobDescriptorBlock->Descriptor[SmramIndex].RegionState = EFI_SMRAM_CLOSED;
    990       }
    991 
    992       SmramIndex++;
    993     }
    994   }
    995 
    996   //
    997   // Build a HOB with the location of the reserved memory range.
    998   //
    999   CopyMem(&DescriptorAcpiVariable, &SmramHobDescriptorBlock->Descriptor[SmramRanges-1], sizeof(EFI_SMRAM_DESCRIPTOR));
   1000   DescriptorAcpiVariable.CpuStart += RESERVED_CPU_S3_SAVE_OFFSET;
   1001   BuildGuidDataHob (
   1002     &gEfiAcpiVariableGuid,
   1003     &DescriptorAcpiVariable,
   1004     sizeof (EFI_SMRAM_DESCRIPTOR)
   1005     );
   1006 
   1007   //
   1008   // Get the location and size of the S3 memory range in the reserved page and
   1009   // install it as PEI Memory.
   1010   //
   1011 
   1012   DEBUG ((EFI_D_INFO, "TSEG Base = 0x%08x\n", SmramHobDescriptorBlock->Descriptor[SmramRanges-1].PhysicalStart));
   1013   S3MemoryRangeData = (RESERVED_ACPI_S3_RANGE*)(UINTN)
   1014     (SmramHobDescriptorBlock->Descriptor[SmramRanges-1].PhysicalStart + RESERVED_ACPI_S3_RANGE_OFFSET);
   1015 
   1016   S3MemoryBase  = (UINTN) (S3MemoryRangeData->AcpiReservedMemoryBase);
   1017   DEBUG ((EFI_D_INFO, "S3MemoryBase = 0x%08x\n", S3MemoryBase));
   1018   S3MemorySize  = (UINTN) (S3MemoryRangeData->AcpiReservedMemorySize);
   1019   DEBUG ((EFI_D_INFO, "S3MemorySize = 0x%08x\n", S3MemorySize));
   1020 
   1021   Status        = PeiServicesInstallPeiMemory (S3MemoryBase, S3MemorySize);
   1022   ASSERT_EFI_ERROR (Status);
   1023 
   1024   //
   1025   // Retrieve the system memory length and build memory hob for the system
   1026   // memory above 1MB. So Memory Callback can set cache for the system memory
   1027   // correctly on S3 boot path, just like it does on Normal boot path.
   1028   //
   1029   ASSERT ((S3MemoryRangeData->SystemMemoryLength - 0x100000) > 0);
   1030   BuildResourceDescriptorHob (
   1031             EFI_RESOURCE_SYSTEM_MEMORY,
   1032             (
   1033             EFI_RESOURCE_ATTRIBUTE_PRESENT |
   1034             EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
   1035             EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
   1036             EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
   1037             EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
   1038             EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
   1039             ),
   1040             0x100000,
   1041             S3MemoryRangeData->SystemMemoryLength - 0x100000
   1042             );
   1043 
   1044   for (Index = 0; Index < NumRanges; Index++) {
   1045     if ((MemoryMap[Index].Type == DualChannelDdrMainMemory) &&
   1046         (MemoryMap[Index].PhysicalAddress + MemoryMap[Index].RangeLength < 0x100000)) {
   1047       BuildResourceDescriptorHob (
   1048         EFI_RESOURCE_SYSTEM_MEMORY,
   1049         (
   1050         EFI_RESOURCE_ATTRIBUTE_PRESENT |
   1051         EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
   1052         EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
   1053         EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
   1054         EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
   1055         EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
   1056         ),
   1057         MemoryMap[Index].PhysicalAddress,
   1058         MemoryMap[Index].RangeLength
   1059         );
   1060       DEBUG ((EFI_D_INFO, "Build resource HOB for Legacy Region on S3 patch :"));
   1061       DEBUG ((EFI_D_INFO, " Memory Base:0x%lX Length:0x%lX\n", MemoryMap[Index].PhysicalAddress, MemoryMap[Index].RangeLength));
   1062     }
   1063   }
   1064 
   1065   return EFI_SUCCESS;
   1066 }
   1067 
   1068 /**
   1069 
   1070   This function returns the memory ranges to be enabled, along with information
   1071   describing how the range should be used.
   1072 
   1073   @param  PeiServices   PEI Services Table.
   1074   @param  TimingData    Detected DDR timing parameters for installed memory.
   1075   @param  RowConfArray  Pointer to an array of EFI_DUAL_CHANNEL_DDR_ROW_CONFIG structures. The number
   1076                         of items in the array must match MaxRows returned by the McGetRowInfo() function.
   1077   @param  MemoryMap     Buffer to record details of the memory ranges tobe enabled.
   1078   @param  NumRanges     On input, this contains the maximum number of memory ranges that can be described
   1079                         in the MemoryMap buffer.
   1080 
   1081   @return MemoryMap     The buffer will be filled in
   1082           NumRanges     will contain the actual number of memory ranges that are to be anabled.
   1083           EFI_SUCCESS   The function completed successfully.
   1084 
   1085 **/
   1086 EFI_STATUS
   1087 GetMemoryMap (
   1088   IN     EFI_PEI_SERVICES                                    **PeiServices,
   1089   IN     UINT32                                              TotalMemorySize,
   1090   IN OUT PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE               *MemoryMap,
   1091   IN OUT UINT8                                               *NumRanges
   1092   )
   1093 {
   1094   EFI_PHYSICAL_ADDRESS              MemorySize;
   1095   EFI_PHYSICAL_ADDRESS              RowLength;
   1096   EFI_STATUS                        Status;
   1097   PEI_MEMORY_RANGE_PCI_MEMORY       PciMemoryMask;
   1098   PEI_MEMORY_RANGE_OPTION_ROM       OptionRomMask;
   1099   PEI_MEMORY_RANGE_SMRAM            SmramMask;
   1100   PEI_MEMORY_RANGE_SMRAM            TsegMask;
   1101   UINT32                            BlockNum;
   1102   UINT8                             ExtendedMemoryIndex;
   1103   UINT32                            Register;
   1104 
   1105   if ((*NumRanges) < MAX_RANGES) {
   1106     return EFI_BUFFER_TOO_SMALL;
   1107   }
   1108 
   1109   *NumRanges = 0;
   1110 
   1111   //
   1112   // Find out which memory ranges to reserve on this platform
   1113   //
   1114   Status = ChooseRanges (
   1115              &OptionRomMask,
   1116              &SmramMask,
   1117              &PciMemoryMask
   1118              );
   1119   ASSERT_EFI_ERROR (Status);
   1120 
   1121   //
   1122   // Generate Memory ranges for the memory map.
   1123   //
   1124   MemorySize = 0;
   1125 
   1126   RowLength = TotalMemorySize;
   1127 
   1128   //
   1129   // Add memory below 640KB to the memory map. Make sure memory between
   1130   // 640KB and 1MB are reserved, even if not used for SMRAM
   1131   //
   1132   MemoryMap[*NumRanges].PhysicalAddress = MemorySize;
   1133   MemoryMap[*NumRanges].CpuAddress      = MemorySize;
   1134   MemoryMap[*NumRanges].RangeLength     = 0xA0000;
   1135   MemoryMap[*NumRanges].Type            = DualChannelDdrMainMemory;
   1136   (*NumRanges)++;
   1137 
   1138   //
   1139   // Just mark this range reserved
   1140   //
   1141   MemoryMap[*NumRanges].PhysicalAddress = 0xA0000;
   1142   MemoryMap[*NumRanges].CpuAddress      = 0xA0000;
   1143   MemoryMap[*NumRanges].RangeLength     = 0x60000;
   1144   MemoryMap[*NumRanges].Type            = DualChannelDdrReservedMemory;
   1145   (*NumRanges)++;
   1146 
   1147   RowLength -= (0x100000 - MemorySize);
   1148   MemorySize = 0x100000;
   1149 
   1150   //
   1151   // Add remaining memory to the memory map
   1152   //
   1153   MemoryMap[*NumRanges].PhysicalAddress = MemorySize;
   1154   MemoryMap[*NumRanges].CpuAddress      = MemorySize;
   1155   MemoryMap[*NumRanges].RangeLength     = RowLength;
   1156   MemoryMap[*NumRanges].Type            = DualChannelDdrMainMemory;
   1157   (*NumRanges)++;
   1158   MemorySize += RowLength;
   1159 
   1160   ExtendedMemoryIndex = (UINT8) (*NumRanges - 1);
   1161 
   1162   // See if we need to trim TSEG out of the highest memory range
   1163   //
   1164   if (SmramMask & PEI_MR_SMRAM_TSEG_MASK) {//pcd
   1165     //
   1166     // Create the new range for TSEG and remove that range from the previous SdrDdrMainMemory range
   1167     //
   1168     TsegMask  = (SmramMask & PEI_MR_SMRAM_SIZE_MASK);
   1169 
   1170     BlockNum  = 1;
   1171     while (TsegMask) {
   1172       TsegMask >>= 1;
   1173       BlockNum <<= 1;
   1174     }
   1175 
   1176     BlockNum >>= 1;
   1177 
   1178     if (BlockNum) {
   1179 
   1180       MemoryMap[*NumRanges].RangeLength           = (BlockNum * 128 * 1024);
   1181       Register = (UINT32)((MemorySize - 1) & SMM_END_MASK);
   1182       MemorySize                                 -= MemoryMap[*NumRanges].RangeLength;
   1183       MemoryMap[*NumRanges].PhysicalAddress       = MemorySize;
   1184       MemoryMap[*NumRanges].CpuAddress            = MemorySize;
   1185       MemoryMap[ExtendedMemoryIndex].RangeLength -= MemoryMap[*NumRanges].RangeLength;
   1186 
   1187       //
   1188       // Update QuarkNcSoc HSMMCTL register
   1189       //
   1190       Register |= (UINT32)(((RShiftU64(MemorySize, 16)) & SMM_START_MASK) + (SMM_WRITE_OPEN | SMM_READ_OPEN | SMM_CODE_RD_OPEN));
   1191       QncHsmmcWrite (Register);
   1192     }
   1193 
   1194     //
   1195     // Chipset only supports cacheable SMRAM
   1196     //
   1197     MemoryMap[*NumRanges].Type = DualChannelDdrSmramCacheable;
   1198 
   1199     (*NumRanges)++;
   1200   }
   1201 
   1202   //
   1203   // trim 64K memory from highest memory range for Rmu Main binary shadow
   1204   //
   1205   MemoryMap[*NumRanges].RangeLength           = 0x10000;
   1206   MemorySize                                 -= MemoryMap[*NumRanges].RangeLength;
   1207   MemoryMap[*NumRanges].PhysicalAddress       = MemorySize;
   1208   MemoryMap[*NumRanges].CpuAddress            = MemorySize;
   1209   MemoryMap[ExtendedMemoryIndex].RangeLength -= MemoryMap[*NumRanges].RangeLength;
   1210   MemoryMap[*NumRanges].Type = DualChannelDdrReservedMemory;
   1211   (*NumRanges)++;
   1212 
   1213   return EFI_SUCCESS;
   1214 }
   1215 
   1216 /**
   1217 
   1218 Routine Description:
   1219 
   1220   Fill in bit masks to specify reserved memory ranges on the Lakeport platform
   1221 
   1222 Arguments:
   1223 
   1224 Returns:
   1225 
   1226   OptionRomMask - Bit mask specifying memory regions reserved for Legacy option
   1227                   ROM use (if any)
   1228 
   1229   SmramMask - Bit mask specifying memory regions reserved for SMM use (if any)
   1230 
   1231 **/
   1232 EFI_STATUS
   1233 ChooseRanges (
   1234   IN OUT   PEI_MEMORY_RANGE_OPTION_ROM           *OptionRomMask,
   1235   IN OUT   PEI_MEMORY_RANGE_SMRAM                *SmramMask,
   1236   IN OUT   PEI_MEMORY_RANGE_PCI_MEMORY           *PciMemoryMask
   1237   )
   1238 {
   1239 
   1240   //
   1241   // Choose regions to reserve for Option ROM use
   1242   //
   1243   *OptionRomMask = PEI_MR_OPTION_ROM_NONE;
   1244 
   1245   //
   1246   // Choose regions to reserve for SMM use (AB/H SEG and TSEG). Size is in 128K blocks
   1247   //
   1248   *SmramMask = PEI_MR_SMRAM_CACHEABLE_MASK | PEI_MR_SMRAM_TSEG_MASK | ((PcdGet32(PcdTSegSize)) >> 17);
   1249 
   1250   *PciMemoryMask = 0;
   1251 
   1252   return EFI_SUCCESS;
   1253 }
   1254 
   1255 EFI_STATUS
   1256 GetPlatformMemorySize (
   1257   IN       EFI_PEI_SERVICES                       **PeiServices,
   1258   IN       EFI_BOOT_MODE                          BootMode,
   1259   IN OUT   UINT64                                 *MemorySize
   1260   )
   1261 {
   1262   EFI_STATUS                            Status;
   1263   EFI_PEI_READ_ONLY_VARIABLE2_PPI       *Variable;
   1264   UINTN                                 DataSize;
   1265   EFI_MEMORY_TYPE_INFORMATION           MemoryData [EfiMaxMemoryType + 1];
   1266   UINTN                                 Index;
   1267 
   1268   DataSize = sizeof (MemoryData);
   1269 
   1270   if (BootMode == BOOT_IN_RECOVERY_MODE) {
   1271 
   1272     //
   1273     // // Treat recovery as if variable not found (eg 1st boot).
   1274     //
   1275     Status = EFI_NOT_FOUND;
   1276 
   1277   } else {
   1278     Status = PeiServicesLocatePpi (
   1279                &gEfiPeiReadOnlyVariable2PpiGuid,
   1280                0,
   1281                NULL,
   1282                (VOID **)&Variable
   1283                );
   1284 
   1285     ASSERT_EFI_ERROR (Status);
   1286 
   1287     DataSize = sizeof (MemoryData);
   1288     Status = Variable->GetVariable (
   1289                          Variable,
   1290                          EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
   1291                          &gEfiMemoryTypeInformationGuid,
   1292                          NULL,
   1293                          &DataSize,
   1294                          &MemoryData
   1295                          );
   1296   }
   1297 
   1298   //
   1299   // Accumulate maximum amount of memory needed
   1300   //
   1301   if (EFI_ERROR (Status)) {
   1302     //
   1303     // Start with minimum memory
   1304     //
   1305     *MemorySize = PEI_MIN_MEMORY_SIZE;
   1306 
   1307     for (Index = 0; Index < sizeof(mDefaultQncMemoryTypeInformation) / sizeof (EFI_MEMORY_TYPE_INFORMATION); Index++) {
   1308         *MemorySize += mDefaultQncMemoryTypeInformation[Index].NumberOfPages * EFI_PAGE_SIZE;
   1309     }
   1310 
   1311     //
   1312     // Build the GUID'd HOB for DXE
   1313     //
   1314     BuildGuidDataHob (
   1315                  &gEfiMemoryTypeInformationGuid,
   1316                  mDefaultQncMemoryTypeInformation,
   1317                  sizeof(mDefaultQncMemoryTypeInformation)
   1318                  );
   1319   } else {
   1320     //
   1321     // Start with at least PEI_MIN_MEMORY_SIZE pages of memory for the DXE Core and the DXE Stack
   1322     //
   1323 
   1324     *MemorySize = PEI_MIN_MEMORY_SIZE;
   1325     for (Index = 0; Index < DataSize / sizeof (EFI_MEMORY_TYPE_INFORMATION); Index++) {
   1326       DEBUG ((EFI_D_INFO, "Index %d, Page: %d\n", Index, MemoryData[Index].NumberOfPages));
   1327       *MemorySize += MemoryData[Index].NumberOfPages * EFI_PAGE_SIZE;
   1328     }
   1329 
   1330     //
   1331     // Build the GUID'd HOB for DXE
   1332     //
   1333     BuildGuidDataHob (
   1334                  &gEfiMemoryTypeInformationGuid,
   1335                  MemoryData,
   1336                  DataSize
   1337                  );
   1338 
   1339   }
   1340 
   1341   return EFI_SUCCESS;
   1342 }
   1343 
   1344 
   1345 EFI_STATUS
   1346 BaseMemoryTest (
   1347   IN  EFI_PEI_SERVICES                   **PeiServices,
   1348   IN  EFI_PHYSICAL_ADDRESS               BeginAddress,
   1349   IN  UINT64                             MemoryLength,
   1350   IN  PEI_MEMORY_TEST_OP                 Operation,
   1351   OUT EFI_PHYSICAL_ADDRESS               *ErrorAddress
   1352   )
   1353 {
   1354   UINT32                TestPattern;
   1355   EFI_PHYSICAL_ADDRESS  TempAddress;
   1356   UINT32                SpanSize;
   1357 
   1358   TestPattern = 0x5A5A5A5A;
   1359   SpanSize    = 0;
   1360 
   1361   //
   1362   // Make sure we don't try and test anything above the max physical address range
   1363   //
   1364   ASSERT (BeginAddress + MemoryLength < MAX_ADDRESS);
   1365 
   1366   switch (Operation) {
   1367   case Extensive:
   1368     SpanSize = 0x4;
   1369     break;
   1370 
   1371   case Sparse:
   1372   case Quick:
   1373     SpanSize = 0x40000;
   1374     break;
   1375 
   1376   case Ignore:
   1377     goto Done;
   1378     break;
   1379   }
   1380   //
   1381   // Write the test pattern into memory range
   1382   //
   1383   TempAddress = BeginAddress;
   1384   while (TempAddress < BeginAddress + MemoryLength) {
   1385     (*(UINT32 *) (UINTN) TempAddress) = TestPattern;
   1386     TempAddress += SpanSize;
   1387   }
   1388   //
   1389   // Read pattern from memory and compare it
   1390   //
   1391   TempAddress = BeginAddress;
   1392   while (TempAddress < BeginAddress + MemoryLength) {
   1393     if ((*(UINT32 *) (UINTN) TempAddress) != TestPattern) {
   1394       *ErrorAddress = TempAddress;
   1395       DEBUG ((EFI_D_ERROR, "Memory test failed at 0x%x.\n", TempAddress));
   1396       return EFI_DEVICE_ERROR;
   1397     }
   1398 
   1399     TempAddress += SpanSize;
   1400   }
   1401 
   1402 Done:
   1403   return EFI_SUCCESS;
   1404 }
   1405 
   1406 /**
   1407 
   1408   This function sets up the platform specific IMR protection for the various
   1409   memory regions.
   1410 
   1411   @param  PeiMemoryBaseAddress  Base address of memory allocated for PEI.
   1412   @param  PeiMemoryLength       Length in bytes of the PEI memory (includes ACPI memory).
   1413 
   1414   @return EFI_SUCCESS           The function completed successfully.
   1415           EFI_ACCESS_DENIED     Access to IMRs failed.
   1416 
   1417 **/
   1418 EFI_STATUS
   1419 SetPlatformImrPolicy (
   1420   IN      EFI_PHYSICAL_ADDRESS    PeiMemoryBaseAddress,
   1421   IN      UINT64                  PeiMemoryLength
   1422   )
   1423 {
   1424   UINT8         Index;
   1425   UINT32        Register;
   1426   UINT16        DeviceId;
   1427 
   1428   //
   1429   // Check what Soc we are running on (read Host bridge DeviceId)
   1430   //
   1431   DeviceId = QNCMmPci16(0, MC_BUS, MC_DEV, MC_FUN, PCI_DEVICE_ID_OFFSET);
   1432 
   1433   //
   1434   // If any IMR register is locked then we cannot proceed
   1435   //
   1436   for (Index = (QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXL); Index <=(QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXL); Index=Index+4)
   1437   {
   1438     Register = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, Index);
   1439     if (Register & IMR_LOCK) {
   1440       return EFI_ACCESS_DENIED;
   1441     }
   1442   }
   1443 
   1444   //
   1445   // Add IMR2 protection for shadowed RMU binary.
   1446   //
   1447   QncImrWrite (
   1448             QUARK_NC_MEMORY_MANAGER_IMR2,
   1449             (UINT32)(((RShiftU64((PeiMemoryBaseAddress+PeiMemoryLength), 8)) & IMRH_MASK) | IMR_EN),
   1450             (UINT32)((RShiftU64((PeiMemoryBaseAddress+PeiMemoryLength+PcdGet32(PcdFlashQNCMicrocodeSize)-1), 8)) & IMRH_MASK),
   1451             (UINT32)(CPU_SNOOP + RMU + CPU0_NON_SMM),
   1452             (UINT32)(CPU_SNOOP + RMU + CPU0_NON_SMM)
   1453         );
   1454 
   1455   //
   1456   // Add IMR3 protection for the default SMRAM.
   1457   //
   1458   QncImrWrite (
   1459             QUARK_NC_MEMORY_MANAGER_IMR3,
   1460             (UINT32)(((RShiftU64((SMM_DEFAULT_SMBASE), 8)) & IMRL_MASK) | IMR_EN),
   1461             (UINT32)((RShiftU64((SMM_DEFAULT_SMBASE+SMM_DEFAULT_SMBASE_SIZE_BYTES-1), 8)) & IMRH_MASK),
   1462             (UINT32)(CPU_SNOOP + CPU0_NON_SMM),
   1463             (UINT32)(CPU_SNOOP + CPU0_NON_SMM)
   1464         );
   1465 
   1466   //
   1467   // Enable IMR4 protection of eSRAM.
   1468   //
   1469   QncImrWrite (
   1470             QUARK_NC_MEMORY_MANAGER_IMR4,
   1471             (UINT32)(((RShiftU64((UINTN)PcdGet32 (PcdEsramStage1Base), 8)) & IMRL_MASK) | IMR_EN),
   1472             (UINT32)((RShiftU64(((UINTN)PcdGet32 (PcdEsramStage1Base) + (UINTN)PcdGet32 (PcdESramMemorySize) - 1), 8)) & IMRH_MASK),
   1473             (UINT32)(CPU_SNOOP + CPU0_NON_SMM),
   1474             (UINT32)(CPU_SNOOP + CPU0_NON_SMM)
   1475         );
   1476 
   1477   //
   1478   // Enable Interrupt on IMR/SMM Violation
   1479   //
   1480   QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_BIMRVCTL, (UINT32)(EnableIMRInt));
   1481   if (DeviceId == QUARK2_MC_DEVICE_ID) {
   1482     QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_BSMMVCTL, (UINT32)(EnableSMMInt));
   1483   }
   1484 
   1485   //
   1486   // Disable IMR7 memory protection (eSRAM + DDR3 memory) since our policies
   1487   // are now setup.
   1488   //
   1489   QncImrWrite (
   1490             QUARK_NC_MEMORY_MANAGER_IMR7,
   1491             (UINT32)(IMRL_RESET & ~IMR_EN),
   1492             (UINT32)IMRH_RESET,
   1493             (UINT32)IMRX_ALL_ACCESS,
   1494             (UINT32)IMRX_ALL_ACCESS
   1495         );
   1496 
   1497   return EFI_SUCCESS;
   1498 }
   1499 
   1500 /** Return info derived from Installing Memory by MemoryInit.
   1501 
   1502   @param[out]      RmuMainBaseAddressPtr   Return RmuMainBaseAddress to this location.
   1503   @param[out]      SmramDescriptorPtr  Return start of Smram descriptor list to this location.
   1504   @param[out]      NumSmramRegionsPtr  Return numbers of Smram regions to this location.
   1505 
   1506   @return Address of RMU shadow region at the top of available memory.
   1507   @return List of Smram descriptors for each Smram region.
   1508   @return Numbers of Smram regions.
   1509 **/
   1510 VOID
   1511 EFIAPI
   1512 InfoPostInstallMemory (
   1513   OUT     UINT32                    *RmuMainBaseAddressPtr OPTIONAL,
   1514   OUT     EFI_SMRAM_DESCRIPTOR      **SmramDescriptorPtr OPTIONAL,
   1515   OUT     UINTN                     *NumSmramRegionsPtr OPTIONAL
   1516   )
   1517 {
   1518   EFI_STATUS                            Status;
   1519   EFI_PEI_HOB_POINTERS                  Hob;
   1520   UINT64                                CalcLength;
   1521   EFI_SMRAM_HOB_DESCRIPTOR_BLOCK        *SmramHobDescriptorBlock;
   1522 
   1523   if ((RmuMainBaseAddressPtr == NULL) && (SmramDescriptorPtr == NULL) && (NumSmramRegionsPtr == NULL)) {
   1524     return;
   1525   }
   1526 
   1527   SmramHobDescriptorBlock = NULL;
   1528   if (SmramDescriptorPtr != NULL) {
   1529     *SmramDescriptorPtr = NULL;
   1530   }
   1531   if (NumSmramRegionsPtr != NULL) {
   1532     *NumSmramRegionsPtr = 0;
   1533   }
   1534 
   1535   //
   1536   // Calculate RMU shadow region base address.
   1537   // Set to 1 MB. Since 1MB cacheability will always be set
   1538   // until override by CSM.
   1539   //
   1540   CalcLength = 0x100000;
   1541 
   1542   Status = PeiServicesGetHobList ((VOID **) &Hob.Raw);
   1543   ASSERT_EFI_ERROR (Status);
   1544   while (!END_OF_HOB_LIST (Hob)) {
   1545     if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
   1546       if (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {
   1547         //
   1548         // Skip the memory region below 1MB
   1549         //
   1550         if (Hob.ResourceDescriptor->PhysicalStart >= 0x100000) {
   1551           CalcLength += (UINT64) (Hob.ResourceDescriptor->ResourceLength);
   1552         }
   1553       }
   1554     } else if (Hob.Header->HobType == EFI_HOB_TYPE_GUID_EXTENSION) {
   1555       if (CompareGuid (&(Hob.Guid->Name), &gEfiSmmPeiSmramMemoryReserveGuid)) {
   1556         SmramHobDescriptorBlock = (VOID*) (Hob.Raw + sizeof (EFI_HOB_GUID_TYPE));
   1557         if (SmramDescriptorPtr != NULL) {
   1558           *SmramDescriptorPtr = SmramHobDescriptorBlock->Descriptor;
   1559         }
   1560         if (NumSmramRegionsPtr != NULL) {
   1561           *NumSmramRegionsPtr = SmramHobDescriptorBlock->NumberOfSmmReservedRegions;
   1562         }
   1563       }
   1564     }
   1565     Hob.Raw = GET_NEXT_HOB (Hob);
   1566   }
   1567 
   1568   if (RmuMainBaseAddressPtr != NULL) {
   1569     *RmuMainBaseAddressPtr = (UINT32) CalcLength;
   1570   }
   1571 }
   1572