2 Framework PEIM to initialize memory on a Quark Memory Controller.
4 Copyright (c) 2013 - 2016, Intel Corporation.
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
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.
16 #include "CommonHeader.h"
17 #include "MrcWrapper.h"
21 #include <Library/PlatformHelperLib.h>
24 // ------------------------ TSEG Base
26 // ------------------------ RESERVED_CPU_S3_SAVE_OFFSET
28 // ------------------------ RESERVED_ACPI_S3_RANGE_OFFSET
29 // S3 Memory base structure
30 // ------------------------ TSEG + 1 page
32 #define RESERVED_CPU_S3_SAVE_OFFSET (RESERVED_ACPI_S3_RANGE_OFFSET - sizeof (SMM_S3_RESUME_STATE))
34 // Strap configuration register specifying DDR setup
35 #define QUARK_SCSS_REG_STPDDRCFG 0x00
37 // Macro counting array elements
38 #define COUNT(a) (sizeof(a)/sizeof(*a))
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 }
51 Configure Uart mmio base for MRC serial log purpose
53 @param MrcData - MRC configuration data updated
66 UartIdx
= PcdGet8(PcdIohUartFunctionNumber
);
67 IohUartBus
= PcdGet8(PcdIohUartBusNumber
);
68 IohUartDev
= PcdGet8(PcdIohUartDevNumber
);
70 RegData32
= PciRead32 (PCI_LIB_ADDRESS(IohUartBus
, IohUartDev
, UartIdx
, PCI_BASE_ADDRESSREG_OFFSET
));
71 MrcData
->uart_mmio_base
= RegData32
& 0xFFFFFFF0;
75 Configure MRC from memory controller fuse settings.
77 @param MrcData - MRC configuration data to be updated.
79 @return EFI_SUCCESS MRC Config parameters updated from platform data.
82 MrcConfigureFromMcFuses (
83 OUT MRC_PARAMS
*MrcData
88 McFuseStat
= QNCPortRead (
89 QUARK_NC_MEMORY_CONTROLLER_SB_PORT_ID
,
90 QUARK_NC_MEMORY_CONTROLLER_REG_DFUSESTAT
93 DEBUG ((EFI_D_INFO
, "MRC McFuseStat 0x%08x\n", McFuseStat
));
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;
99 MrcData
->ecc_enables
= 1;
105 Configure MRC from platform info hob.
107 @param MrcData - MRC configuration data to be updated.
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.
114 MrcConfigureFromInfoHob (
115 OUT MRC_PARAMS
*MrcData
118 PDAT_MRC_ITEM
*ItemData
;
120 ItemData
= (PDAT_MRC_ITEM
*)PcdGetPtr (PcdMrcParameters
);
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
;
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
;
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
""
152 DEBUG ((EFI_D_INFO
, "MRC density=%d tCL=%d tRAS=%d tWTR=%d tRRD=%d tFAW=%d\n",
153 MrcData
->params
.DENSITY
,
155 MrcData
->params
.tRAS
,
156 MrcData
->params
.tWTR
,
157 MrcData
->params
.tRRD
,
168 @param MrcData - MRC configuration
173 const MRC_PARAMS
*MrcData
177 UINT32 EndAdr
= MrcData
->mem_size
;
178 UINT32 BlkSize
= PcdGet8(PcdEccScrubBlkSize
) & SCRUB_CFG_BLOCKSIZE_MASK
;
179 UINT32 Interval
= PcdGet8(PcdEccScrubInterval
) & SCRUB_CFG_INTERVAL_MASK
;
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.
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
);
196 McD0PciCfg32 (QNC_ACCESS_PORT_MCR
) = SCRUB_RESUME_MSG();
199 /** Post InstallS3Memory / InstallEfiMemory tasks given MrcData context.
201 @param[in] MrcData MRC configuration.
202 @param[in] IsS3 TRUE if after InstallS3Memory.
207 IN MRC_PARAMS
*MrcData
,
211 UINT32 RmuMainDestBaseAddress
;
212 UINT32
*RmuMainSrcBaseAddress
;
217 // Setup ECC policy (All boot modes).
219 QNCPolicyDblEccBitErr (V_WDT_CONTROL_DBL_ECC_BIT_ERR_WARM
);
222 // Find the 64KB of memory for Rmu Main at the top of available memory.
224 InfoPostInstallMemory (&RmuMainDestBaseAddress
, NULL
, NULL
);
225 DEBUG ((EFI_D_INFO
, "RmuMain Base Address : 0x%x\n", RmuMainDestBaseAddress
));
231 QNCSendOpcodeDramReady (RmuMainDestBaseAddress
);
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
));
239 RmuMainRelocation (RmuMainDestBaseAddress
, (UINT32
) RmuMainSrcBaseAddress
, RmuMainSize
);
240 QNCSendOpcodeDramReady (RmuMainDestBaseAddress
);
241 EccScrubSetup (MrcData
);
247 Do memory initialisation for QNC DDR3 SDRAM Controller
249 @param FfsHeader Not used.
250 @param PeiServices General purpose services available to every PEIM.
252 @return EFI_SUCCESS Memory initialisation completed successfully.
253 All other error conditions encountered result in an ASSERT.
258 IN EFI_PEI_SERVICES
**PeiServices
262 EFI_BOOT_MODE BootMode
;
264 EFI_PEI_READ_ONLY_VARIABLE2_PPI
*VariableServices
;
265 EFI_STATUS_CODE_VALUE ErrorCodeValue
;
266 PEI_QNC_MEMORY_INIT_PPI
*QncMemoryInitPpi
;
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.
279 ZeroMem (&MrcData
, sizeof(MrcData
));
284 Status
= PeiServicesLocatePpi (
285 &gEfiPeiReadOnlyVariable2PpiGuid
, // GUID
287 NULL
, // EFI_PEI_PPI_DESCRIPTOR
288 (VOID
**)&VariableServices
// PPI
290 ASSERT_EFI_ERROR (Status
);
293 // Determine boot mode
295 Status
= PeiServicesGetBootMode (&BootMode
);
296 ASSERT_EFI_ERROR (Status
);
299 // Initialize Error type for reporting status code
302 case BOOT_ON_FLASH_UPDATE
:
303 ErrorCodeValue
= EFI_COMPUTING_UNIT_MEMORY
+ EFI_CU_MEMORY_EC_UPDATE_FAIL
;
305 case BOOT_ON_S3_RESUME
:
306 ErrorCodeValue
= EFI_COMPUTING_UNIT_MEMORY
+ EFI_CU_MEMORY_EC_S3_RESUME_FAIL
;
309 ErrorCodeValue
= EFI_COMPUTING_UNIT_MEMORY
;
314 // Specify MRC boot mode
317 case BOOT_ON_S3_RESUME
:
318 case BOOT_ON_FLASH_UPDATE
:
319 MrcData
.boot_mode
= bmS3
;
321 case BOOT_ASSUMING_NO_CONFIGURATION_CHANGES
:
322 MrcData
.boot_mode
= bmFast
;
325 MrcData
.boot_mode
= bmCold
;
330 // Configure MRC input parameters.
332 Status
= MrcConfigureFromMcFuses (&MrcData
);
333 ASSERT_EFI_ERROR (Status
);
334 Status
= MrcConfigureFromInfoHob (&MrcData
);
335 ASSERT_EFI_ERROR (Status
);
336 MrcUartConfig(&MrcData
);
338 if (BootMode
== BOOT_IN_RECOVERY_MODE
) {
340 // Always do bmCold on recovery.
342 DEBUG ((DEBUG_INFO
, "MemoryInit:Force bmCold on Recovery\n"));
343 MrcData
.boot_mode
= bmCold
;
347 // Load Memory configuration data saved in previous boot from variable
349 Status
= LoadConfig (
355 if (EFI_ERROR (Status
)) {
358 case BOOT_ON_S3_RESUME
:
359 case BOOT_ON_FLASH_UPDATE
:
361 EFI_ERROR_CODE
+ EFI_ERROR_UNRECOVERED
,
364 PeiServicesResetSystem ();
368 MrcData
.boot_mode
= bmCold
;
375 // Locate Memory Reference Code PPI
377 Status
= PeiServicesLocatePpi (
378 &gQNCMemoryInitPpiGuid
, // GUID
380 NULL
, // EFI_PEI_PPI_DESCRIPTOR
381 (VOID
**)&QncMemoryInitPpi
// PPI
383 ASSERT_EFI_ERROR (Status
);
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
;
392 IoOr32 (PmswAdr
, (UINT32
)B_QNC_GPE0BLK_PMSW_DRAM_INIT
);
395 // Call Memory Reference Code's Routines
397 QncMemoryInitPpi
->MrcStart (&MrcData
);
399 // Mark MRC completed
400 IoAnd32 (PmswAdr
, ~(UINT32
)B_QNC_GPE0BLK_PMSW_DRAM_INIT
);
404 // Note emulation platform has to read actual memory size
405 // MrcData.mem_size from PcdGet32 (PcdMemorySize);
407 if (BootMode
== BOOT_ON_S3_RESUME
) {
409 DEBUG ((EFI_D_INFO
, "Following BOOT_ON_S3_RESUME boot path.\n"));
411 Status
= InstallS3Memory (PeiServices
, VariableServices
, MrcData
.mem_size
);
412 if (EFI_ERROR (Status
)) {
414 EFI_ERROR_CODE
+ EFI_ERROR_UNRECOVERED
,
417 PeiServicesResetSystem ();
419 PostInstallMemory (&MrcData
, TRUE
);
424 // Assign physical memory to PEI and DXE
426 DEBUG ((EFI_D_INFO
, "InstallEfiMemory.\n"));
428 Status
= InstallEfiMemory (
434 ASSERT_EFI_ERROR (Status
);
436 PostInstallMemory (&MrcData
, FALSE
);
439 // Save current configuration into Hob and will save into Variable later in DXE
441 DEBUG ((EFI_D_INFO
, "SaveConfig.\n"));
442 Status
= SaveConfig (
445 ASSERT_EFI_ERROR (Status
);
447 DEBUG ((EFI_D_INFO
, "MemoryInit Complete.\n"));
454 This function saves a config to a HOB.
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.
461 @return EFI_SUCCESS: The function completed successfully.
466 IN MRC_PARAMS
*MrcData
470 // Build HOB data for Memory Config
471 // HOB data size (stored in variable) is required to be multiple of 8 bytes
474 &gEfiMemoryConfigDataGuid
,
475 (VOID
*) &MrcData
->timings
,
476 ((sizeof (MrcData
->timings
) + 0x7) & (~0x7))
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
)));
487 Load a configuration stored in a variable.
489 @param TimingData Timing data to be loaded from NVRAM.
490 @param RowConfArray Row configuration information for each row in the system.
492 @return EFI_SUCCESS The function completed successfully.
493 Other Could not read variable.
498 IN EFI_PEI_SERVICES
**PeiServices
,
499 IN EFI_PEI_READ_ONLY_VARIABLE2_PPI
*VariableServices
,
500 IN OUT MRC_PARAMS
*MrcData
505 PLATFORM_VARIABLE_MEMORY_CONFIG_DATA VarData
;
507 BufferSize
= ((sizeof (VarData
.timings
) + 0x7) & (~0x7)); // HOB data size (stored in variable) is required to be multiple of 8bytes
509 Status
= VariableServices
->GetVariable (
511 EFI_MEMORY_CONFIG_DATA_NAME
,
512 &gEfiMemoryConfigDataGuid
,
517 if (!EFI_ERROR (Status
)) {
518 CopyMem (&MrcData
->timings
, &VarData
.timings
, sizeof(MrcData
->timings
));
525 This function installs memory.
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.
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.
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
545 EFI_PHYSICAL_ADDRESS PeiMemoryBaseAddress
;
546 EFI_SMRAM_HOB_DESCRIPTOR_BLOCK
*SmramHobDescriptorBlock
;
548 EFI_PEI_HOB_POINTERS Hob
;
549 PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE MemoryMap
[MAX_RANGES
];
554 UINT64 PeiMemoryLength
;
556 UINTN PeiMemoryIndex
;
557 UINTN RequiredMemSize
;
558 EFI_RESOURCE_ATTRIBUTE_TYPE Attribute
;
559 EFI_PHYSICAL_ADDRESS BadMemoryAddress
;
560 EFI_SMRAM_DESCRIPTOR DescriptorAcpiVariable
;
562 UINTN CapsuleBufferLength
;
563 PEI_CAPSULE_PPI
*Capsule
;
564 VOID
*LargeMemRangeBuf
;
565 UINTN LargeMemRangeBufLen
;
570 // Test the memory from 1M->TOM
572 if (BootMode
!= BOOT_ON_FLASH_UPDATE
) {
573 Status
= BaseMemoryTest (
576 (TotalMemorySize
- 0x100000),
580 ASSERT_EFI_ERROR (Status
);
585 // Get the Memory Map
587 NumRanges
= MAX_RANGES
;
589 ZeroMem (MemoryMap
, sizeof (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE
) * NumRanges
);
591 Status
= GetMemoryMap (
594 (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE
*) MemoryMap
,
597 ASSERT_EFI_ERROR (Status
);
600 // Find the highest memory range in processor native address space to give to
601 // PEI. Then take the top.
603 PeiMemoryBaseAddress
= 0;
606 // Query the platform for the minimum memory size
609 Status
= GetPlatformMemorySize (
614 ASSERT_EFI_ERROR (Status
);
617 // Get required memory size for ACPI use. This helps to put ACPI memory on the topest
620 RetriveRequiredMemorySize (PeiServices
, &RequiredMemSize
);
623 // Detect MOR request by the OS.
626 DataSize
= sizeof (MorControl
);
627 Status
= VariableServices
->GetVariable (
629 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME
,
630 &gEfiMemoryOverwriteControlDataGuid
,
638 for (Index
= 0; Index
< NumRanges
; Index
++)
640 DEBUG ((EFI_D_INFO
, "Found 0x%x bytes at ", MemoryMap
[Index
].RangeLength
));
641 DEBUG ((EFI_D_INFO
, "0x%x.\n", MemoryMap
[Index
].PhysicalAddress
));
644 // If OS requested a memory overwrite perform it now. Only do it for memory
647 if (MOR_CLEAR_MEMORY_VALUE (MorControl
) && MemoryMap
[Index
].Type
== DualChannelDdrMainMemory
) {
648 DEBUG ((EFI_D_INFO
, "Clear memory per MOR request.\n"));
649 if ((UINTN
)MemoryMap
[Index
].RangeLength
> 0) {
650 if ((UINTN
)MemoryMap
[Index
].PhysicalAddress
== 0) {
652 // ZeroMem() generates an ASSERT() if Buffer parameter is NULL.
653 // Clear byte at 0 and start clear operation at address 1.
656 ZeroMem ((VOID
*)1, (UINTN
)MemoryMap
[Index
].RangeLength
- 1);
659 (VOID
*)(UINTN
)MemoryMap
[Index
].PhysicalAddress
,
660 (UINTN
)MemoryMap
[Index
].RangeLength
666 if ((MemoryMap
[Index
].Type
== DualChannelDdrMainMemory
) &&
667 (MemoryMap
[Index
].PhysicalAddress
+ MemoryMap
[Index
].RangeLength
< MAX_ADDRESS
) &&
668 (MemoryMap
[Index
].PhysicalAddress
>= PeiMemoryBaseAddress
) &&
669 (MemoryMap
[Index
].RangeLength
>= PeiMemoryLength
)) {
670 PeiMemoryBaseAddress
= MemoryMap
[Index
].PhysicalAddress
+
671 MemoryMap
[Index
].RangeLength
-
673 PeiMemoryIndex
= Index
;
678 // Find the largest memory range excluding that given to PEI.
680 LargeMemRangeBuf
= NULL
;
681 LargeMemRangeBufLen
= 0;
682 for (Index
= 0; Index
< NumRanges
; Index
++) {
683 if ((MemoryMap
[Index
].Type
== DualChannelDdrMainMemory
) &&
684 (MemoryMap
[Index
].PhysicalAddress
+ MemoryMap
[Index
].RangeLength
< MAX_ADDRESS
)) {
685 if (Index
!= PeiMemoryIndex
) {
686 if (MemoryMap
[Index
].RangeLength
> LargeMemRangeBufLen
) {
687 LargeMemRangeBuf
= (VOID
*) ((UINTN
) MemoryMap
[Index
].PhysicalAddress
);
688 LargeMemRangeBufLen
= (UINTN
) MemoryMap
[Index
].RangeLength
;
691 if ((MemoryMap
[Index
].RangeLength
- PeiMemoryLength
) >= LargeMemRangeBufLen
) {
692 LargeMemRangeBuf
= (VOID
*) ((UINTN
) MemoryMap
[Index
].PhysicalAddress
);
693 LargeMemRangeBufLen
= (UINTN
) (MemoryMap
[Index
].RangeLength
- PeiMemoryLength
);
700 CapsuleBuffer
= NULL
;
701 CapsuleBufferLength
= 0;
702 if (BootMode
== BOOT_ON_FLASH_UPDATE
) {
703 Status
= PeiServicesLocatePpi (
704 &gPeiCapsulePpiGuid
, // GUID
706 NULL
, // EFI_PEI_PPI_DESCRIPTOR
707 (VOID
**)&Capsule
// PPI
709 ASSERT_EFI_ERROR (Status
);
711 if (Status
== EFI_SUCCESS
) {
712 CapsuleBuffer
= LargeMemRangeBuf
;
713 CapsuleBufferLength
= LargeMemRangeBufLen
;
716 // Call the Capsule PPI Coalesce function to coalesce the capsule data.
718 Status
= Capsule
->Coalesce (
724 // If it failed, then NULL out our capsule PPI pointer so that the capsule
725 // HOB does not get created below.
727 if (Status
!= EFI_SUCCESS
) {
734 // Set up the IMR policy required for this platform
736 Status
= SetPlatformImrPolicy (
737 PeiMemoryBaseAddress
,
741 ASSERT_EFI_ERROR (Status
);
744 // Carve out the top memory reserved for ACPI
746 Status
= PeiServicesInstallPeiMemory (PeiMemoryBaseAddress
, (PeiMemoryLength
- RequiredMemSize
));
747 ASSERT_EFI_ERROR (Status
);
749 BuildResourceDescriptorHob (
750 EFI_RESOURCE_SYSTEM_MEMORY
, // MemoryType,
752 EFI_RESOURCE_ATTRIBUTE_PRESENT
|
753 EFI_RESOURCE_ATTRIBUTE_INITIALIZED
|
754 EFI_RESOURCE_ATTRIBUTE_TESTED
|
755 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE
|
756 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE
|
757 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE
|
758 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
760 PeiMemoryBaseAddress
, // MemoryBegin
761 PeiMemoryLength
// MemoryLength
765 // Install physical memory descriptor hobs for each memory range.
768 for (Index
= 0; Index
< NumRanges
; Index
++) {
770 if (MemoryMap
[Index
].Type
== DualChannelDdrMainMemory
)
772 if (Index
== PeiMemoryIndex
) {
774 // This is a partially tested Main Memory range, give it to EFI
776 BuildResourceDescriptorHob (
777 EFI_RESOURCE_SYSTEM_MEMORY
,
779 EFI_RESOURCE_ATTRIBUTE_PRESENT
|
780 EFI_RESOURCE_ATTRIBUTE_INITIALIZED
|
781 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE
|
782 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE
|
783 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE
|
784 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
786 MemoryMap
[Index
].PhysicalAddress
,
787 MemoryMap
[Index
].RangeLength
- PeiMemoryLength
791 // This is an untested Main Memory range, give it to EFI
793 BuildResourceDescriptorHob (
794 EFI_RESOURCE_SYSTEM_MEMORY
, // MemoryType,
796 EFI_RESOURCE_ATTRIBUTE_PRESENT
|
797 EFI_RESOURCE_ATTRIBUTE_INITIALIZED
|
798 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE
|
799 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE
|
800 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE
|
801 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
803 MemoryMap
[Index
].PhysicalAddress
, // MemoryBegin
804 MemoryMap
[Index
].RangeLength
// MemoryLength
808 if ((MemoryMap
[Index
].Type
== DualChannelDdrSmramCacheable
) ||
809 (MemoryMap
[Index
].Type
== DualChannelDdrSmramNonCacheable
)) {
812 if ((MemoryMap
[Index
].Type
== DualChannelDdrSmramNonCacheable
) ||
813 (MemoryMap
[Index
].Type
== DualChannelDdrGraphicsMemoryNonCacheable
)) {
814 Attribute
|= EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE
;
816 if ((MemoryMap
[Index
].Type
== DualChannelDdrSmramCacheable
) ||
817 (MemoryMap
[Index
].Type
== DualChannelDdrGraphicsMemoryCacheable
)) {
819 // TSEG and HSEG can be used with a write-back(WB) cache policy; however,
820 // the specification requires that the TSEG and HSEG space be cached only
821 // inside of the SMI handler. when using HSEG or TSEG an IA-32 processor
822 // does not automatically write back and invalidate its cache before entering
823 // SMM or before existing SMM therefore any MTRR defined for the active TSEG
824 // or HSEG must be set to un-cacheable(UC) outside of SMM.
826 Attribute
|= EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
| EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE
;
828 if (MemoryMap
[Index
].Type
== DualChannelDdrReservedMemory
) {
829 Attribute
|= EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
|
830 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE
;
833 // Make sure non-system memory is marked as reserved
835 BuildResourceDescriptorHob (
836 EFI_RESOURCE_MEMORY_RESERVED
, // MemoryType,
837 Attribute
, // MemoryAttribute
838 MemoryMap
[Index
].PhysicalAddress
, // MemoryBegin
839 MemoryMap
[Index
].RangeLength
// MemoryLength
845 // Allocate one extra EFI_SMRAM_DESCRIPTOR to describe a page of SMRAM memory that contains a pointer
846 // to the SMM Services Table that is required on the S3 resume path
848 ASSERT (SmramRanges
> 0);
849 BufferSize
= sizeof (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK
);
850 BufferSize
+= ((SmramRanges
- 1) * sizeof (EFI_SMRAM_DESCRIPTOR
));
852 Hob
.Raw
= BuildGuidHob (
853 &gEfiSmmPeiSmramMemoryReserveGuid
,
858 SmramHobDescriptorBlock
= (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK
*) (Hob
.Raw
);
859 SmramHobDescriptorBlock
->NumberOfSmmReservedRegions
= SmramRanges
;
862 for (Index
= 0; Index
< NumRanges
; Index
++) {
863 if ((MemoryMap
[Index
].Type
== DualChannelDdrSmramCacheable
) ||
864 (MemoryMap
[Index
].Type
== DualChannelDdrSmramNonCacheable
)
867 // This is an SMRAM range, create an SMRAM descriptor
869 SmramHobDescriptorBlock
->Descriptor
[SmramIndex
].PhysicalStart
= MemoryMap
[Index
].PhysicalAddress
;
870 SmramHobDescriptorBlock
->Descriptor
[SmramIndex
].CpuStart
= MemoryMap
[Index
].CpuAddress
;
871 SmramHobDescriptorBlock
->Descriptor
[SmramIndex
].PhysicalSize
= MemoryMap
[Index
].RangeLength
;
872 if (MemoryMap
[Index
].Type
== DualChannelDdrSmramCacheable
) {
873 SmramHobDescriptorBlock
->Descriptor
[SmramIndex
].RegionState
= EFI_SMRAM_CLOSED
| EFI_CACHEABLE
;
875 SmramHobDescriptorBlock
->Descriptor
[SmramIndex
].RegionState
= EFI_SMRAM_CLOSED
;
883 // Build a HOB with the location of the reserved memory range.
885 CopyMem(&DescriptorAcpiVariable
, &SmramHobDescriptorBlock
->Descriptor
[SmramRanges
-1], sizeof(EFI_SMRAM_DESCRIPTOR
));
886 DescriptorAcpiVariable
.CpuStart
+= RESERVED_CPU_S3_SAVE_OFFSET
;
888 &gEfiAcpiVariableGuid
,
889 &DescriptorAcpiVariable
,
890 sizeof (EFI_SMRAM_DESCRIPTOR
)
894 // If we found the capsule PPI (and we didn't have errors), then
895 // call the capsule PEIM to allocate memory for the capsule.
897 if (Capsule
!= NULL
) {
898 Status
= Capsule
->CreateState (PeiServices
, CapsuleBuffer
, CapsuleBufferLength
);
906 Find memory that is reserved so PEI has some to use.
908 @param PeiServices PEI Services table.
909 @param VariableSevices Variable PPI instance.
911 @return EFI_SUCCESS The function completed successfully.
912 Error value from LocatePpi()
913 Error Value from VariableServices->GetVariable()
918 IN EFI_PEI_SERVICES
**PeiServices
,
919 IN EFI_PEI_READ_ONLY_VARIABLE2_PPI
*VariableServices
,
920 IN UINT32 TotalMemorySize
931 EFI_PEI_HOB_POINTERS Hob
;
932 EFI_SMRAM_HOB_DESCRIPTOR_BLOCK
*SmramHobDescriptorBlock
;
933 PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE MemoryMap
[MAX_RANGES
];
934 RESERVED_ACPI_S3_RANGE
*S3MemoryRangeData
;
935 EFI_SMRAM_DESCRIPTOR DescriptorAcpiVariable
;
938 // Get the Memory Map
940 NumRanges
= MAX_RANGES
;
942 ZeroMem (MemoryMap
, sizeof (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE
) * NumRanges
);
944 Status
= GetMemoryMap (
947 (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE
*) MemoryMap
,
950 ASSERT_EFI_ERROR (Status
);
953 // Install physical memory descriptor hobs for each memory range.
956 for (Index
= 0; Index
< NumRanges
; Index
++) {
957 if ((MemoryMap
[Index
].Type
== DualChannelDdrSmramCacheable
) ||
958 (MemoryMap
[Index
].Type
== DualChannelDdrSmramNonCacheable
)) {
963 ASSERT (SmramRanges
> 0);
966 // Allocate one extra EFI_SMRAM_DESCRIPTOR to describe a page of SMRAM memory that contains a pointer
967 // to the SMM Services Table that is required on the S3 resume path
969 BufferSize
= sizeof (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK
);
970 if (SmramRanges
> 0) {
971 BufferSize
+= ((SmramRanges
- 1) * sizeof (EFI_SMRAM_DESCRIPTOR
));
974 Hob
.Raw
= BuildGuidHob (
975 &gEfiSmmPeiSmramMemoryReserveGuid
,
980 SmramHobDescriptorBlock
= (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK
*) (Hob
.Raw
);
981 SmramHobDescriptorBlock
->NumberOfSmmReservedRegions
= SmramRanges
;
984 for (Index
= 0; Index
< NumRanges
; Index
++) {
985 if ((MemoryMap
[Index
].Type
== DualChannelDdrSmramCacheable
) ||
986 (MemoryMap
[Index
].Type
== DualChannelDdrSmramNonCacheable
)
989 // This is an SMRAM range, create an SMRAM descriptor
991 SmramHobDescriptorBlock
->Descriptor
[SmramIndex
].PhysicalStart
= MemoryMap
[Index
].PhysicalAddress
;
992 SmramHobDescriptorBlock
->Descriptor
[SmramIndex
].CpuStart
= MemoryMap
[Index
].CpuAddress
;
993 SmramHobDescriptorBlock
->Descriptor
[SmramIndex
].PhysicalSize
= MemoryMap
[Index
].RangeLength
;
994 if (MemoryMap
[Index
].Type
== DualChannelDdrSmramCacheable
) {
995 SmramHobDescriptorBlock
->Descriptor
[SmramIndex
].RegionState
= EFI_SMRAM_CLOSED
| EFI_CACHEABLE
;
997 SmramHobDescriptorBlock
->Descriptor
[SmramIndex
].RegionState
= EFI_SMRAM_CLOSED
;
1005 // Build a HOB with the location of the reserved memory range.
1007 CopyMem(&DescriptorAcpiVariable
, &SmramHobDescriptorBlock
->Descriptor
[SmramRanges
-1], sizeof(EFI_SMRAM_DESCRIPTOR
));
1008 DescriptorAcpiVariable
.CpuStart
+= RESERVED_CPU_S3_SAVE_OFFSET
;
1010 &gEfiAcpiVariableGuid
,
1011 &DescriptorAcpiVariable
,
1012 sizeof (EFI_SMRAM_DESCRIPTOR
)
1016 // Get the location and size of the S3 memory range in the reserved page and
1017 // install it as PEI Memory.
1020 DEBUG ((EFI_D_INFO
, "TSEG Base = 0x%08x\n", SmramHobDescriptorBlock
->Descriptor
[SmramRanges
-1].PhysicalStart
));
1021 S3MemoryRangeData
= (RESERVED_ACPI_S3_RANGE
*)(UINTN
)
1022 (SmramHobDescriptorBlock
->Descriptor
[SmramRanges
-1].PhysicalStart
+ RESERVED_ACPI_S3_RANGE_OFFSET
);
1024 S3MemoryBase
= (UINTN
) (S3MemoryRangeData
->AcpiReservedMemoryBase
);
1025 DEBUG ((EFI_D_INFO
, "S3MemoryBase = 0x%08x\n", S3MemoryBase
));
1026 S3MemorySize
= (UINTN
) (S3MemoryRangeData
->AcpiReservedMemorySize
);
1027 DEBUG ((EFI_D_INFO
, "S3MemorySize = 0x%08x\n", S3MemorySize
));
1029 Status
= PeiServicesInstallPeiMemory (S3MemoryBase
, S3MemorySize
);
1030 ASSERT_EFI_ERROR (Status
);
1033 // Retrieve the system memory length and build memory hob for the system
1034 // memory above 1MB. So Memory Callback can set cache for the system memory
1035 // correctly on S3 boot path, just like it does on Normal boot path.
1037 ASSERT_EFI_ERROR ((S3MemoryRangeData
->SystemMemoryLength
- 0x100000) > 0);
1038 BuildResourceDescriptorHob (
1039 EFI_RESOURCE_SYSTEM_MEMORY
,
1041 EFI_RESOURCE_ATTRIBUTE_PRESENT
|
1042 EFI_RESOURCE_ATTRIBUTE_INITIALIZED
|
1043 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE
|
1044 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE
|
1045 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE
|
1046 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
1049 S3MemoryRangeData
->SystemMemoryLength
- 0x100000
1052 for (Index
= 0; Index
< NumRanges
; Index
++) {
1053 if ((MemoryMap
[Index
].Type
== DualChannelDdrMainMemory
) &&
1054 (MemoryMap
[Index
].PhysicalAddress
+ MemoryMap
[Index
].RangeLength
< 0x100000)) {
1055 BuildResourceDescriptorHob (
1056 EFI_RESOURCE_SYSTEM_MEMORY
,
1058 EFI_RESOURCE_ATTRIBUTE_PRESENT
|
1059 EFI_RESOURCE_ATTRIBUTE_INITIALIZED
|
1060 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE
|
1061 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE
|
1062 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE
|
1063 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
1065 MemoryMap
[Index
].PhysicalAddress
,
1066 MemoryMap
[Index
].RangeLength
1068 DEBUG ((EFI_D_INFO
, "Build resource HOB for Legacy Region on S3 patch :"));
1069 DEBUG ((EFI_D_INFO
, " Memory Base:0x%lX Length:0x%lX\n", MemoryMap
[Index
].PhysicalAddress
, MemoryMap
[Index
].RangeLength
));
1078 This function returns the size, in bytes, required for the DXE phase.
1080 @param PeiServices PEI Services table.
1081 @param Size Pointer to the size, in bytes, required for the DXE phase.
1087 RetriveRequiredMemorySize (
1088 IN EFI_PEI_SERVICES
**PeiServices
,
1092 EFI_PEI_HOB_POINTERS Hob
;
1093 EFI_MEMORY_TYPE_INFORMATION
*MemoryData
;
1101 PeiServicesGetHobList ((VOID
**)&Hob
.Raw
);
1102 while (!END_OF_HOB_LIST (Hob
)) {
1103 if (Hob
.Header
->HobType
== EFI_HOB_TYPE_GUID_EXTENSION
&&
1104 CompareGuid (&Hob
.Guid
->Name
, &gEfiMemoryTypeInformationGuid
)
1106 MemoryData
= (EFI_MEMORY_TYPE_INFORMATION
*) (Hob
.Raw
+ sizeof (EFI_HOB_GENERIC_HEADER
) + sizeof (EFI_GUID
));
1110 Hob
.Raw
= GET_NEXT_HOB (Hob
);
1113 // Platform PEIM should supply such a information. Generic PEIM doesn't assume any default value
1119 while (MemoryData
[Index
].Type
!= EfiMaxMemoryType
) {
1121 // Accumulate default memory size requirements
1123 TempPageNum
+= MemoryData
[Index
].NumberOfPages
;
1127 if (TempPageNum
== 0) {
1132 // Add additional pages used by DXE memory manager
1134 (*Size
) = (TempPageNum
+ EDKII_DXE_MEM_SIZE_PAGES
) * EFI_PAGE_SIZE
;
1141 This function returns the memory ranges to be enabled, along with information
1142 describing how the range should be used.
1144 @param PeiServices PEI Services Table.
1145 @param TimingData Detected DDR timing parameters for installed memory.
1146 @param RowConfArray Pointer to an array of EFI_DUAL_CHANNEL_DDR_ROW_CONFIG structures. The number
1147 of items in the array must match MaxRows returned by the McGetRowInfo() function.
1148 @param MemoryMap Buffer to record details of the memory ranges tobe enabled.
1149 @param NumRanges On input, this contains the maximum number of memory ranges that can be described
1150 in the MemoryMap buffer.
1152 @return MemoryMap The buffer will be filled in
1153 NumRanges will contain the actual number of memory ranges that are to be anabled.
1154 EFI_SUCCESS The function completed successfully.
1159 IN EFI_PEI_SERVICES
**PeiServices
,
1160 IN UINT32 TotalMemorySize
,
1161 IN OUT PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE
*MemoryMap
,
1162 IN OUT UINT8
*NumRanges
1165 EFI_PHYSICAL_ADDRESS MemorySize
;
1166 EFI_PHYSICAL_ADDRESS RowLength
;
1168 PEI_MEMORY_RANGE_PCI_MEMORY PciMemoryMask
;
1169 PEI_MEMORY_RANGE_OPTION_ROM OptionRomMask
;
1170 PEI_MEMORY_RANGE_SMRAM SmramMask
;
1171 PEI_MEMORY_RANGE_SMRAM TsegMask
;
1173 UINT8 ExtendedMemoryIndex
;
1176 if ((*NumRanges
) < MAX_RANGES
) {
1177 return EFI_BUFFER_TOO_SMALL
;
1183 // Find out which memory ranges to reserve on this platform
1185 Status
= ChooseRanges (
1190 ASSERT_EFI_ERROR (Status
);
1193 // Generate Memory ranges for the memory map.
1197 RowLength
= TotalMemorySize
;
1200 // Add memory below 640KB to the memory map. Make sure memory between
1201 // 640KB and 1MB are reserved, even if not used for SMRAM
1203 MemoryMap
[*NumRanges
].PhysicalAddress
= MemorySize
;
1204 MemoryMap
[*NumRanges
].CpuAddress
= MemorySize
;
1205 MemoryMap
[*NumRanges
].RangeLength
= 0xA0000;
1206 MemoryMap
[*NumRanges
].Type
= DualChannelDdrMainMemory
;
1210 // Just mark this range reserved
1212 MemoryMap
[*NumRanges
].PhysicalAddress
= 0xA0000;
1213 MemoryMap
[*NumRanges
].CpuAddress
= 0xA0000;
1214 MemoryMap
[*NumRanges
].RangeLength
= 0x60000;
1215 MemoryMap
[*NumRanges
].Type
= DualChannelDdrReservedMemory
;
1218 RowLength
-= (0x100000 - MemorySize
);
1219 MemorySize
= 0x100000;
1222 // Add remaining memory to the memory map
1224 MemoryMap
[*NumRanges
].PhysicalAddress
= MemorySize
;
1225 MemoryMap
[*NumRanges
].CpuAddress
= MemorySize
;
1226 MemoryMap
[*NumRanges
].RangeLength
= RowLength
;
1227 MemoryMap
[*NumRanges
].Type
= DualChannelDdrMainMemory
;
1229 MemorySize
+= RowLength
;
1231 ExtendedMemoryIndex
= (UINT8
) (*NumRanges
- 1);
1233 // See if we need to trim TSEG out of the highest memory range
1235 if (SmramMask
& PEI_MR_SMRAM_TSEG_MASK
) {//pcd
1237 // Create the new range for TSEG and remove that range from the previous SdrDdrMainMemory range
1239 TsegMask
= (SmramMask
& PEI_MR_SMRAM_SIZE_MASK
);
1251 MemoryMap
[*NumRanges
].RangeLength
= (BlockNum
* 128 * 1024);
1252 Register
= (UINT32
)((MemorySize
- 1) & SMM_END_MASK
);
1253 MemorySize
-= MemoryMap
[*NumRanges
].RangeLength
;
1254 MemoryMap
[*NumRanges
].PhysicalAddress
= MemorySize
;
1255 MemoryMap
[*NumRanges
].CpuAddress
= MemorySize
;
1256 MemoryMap
[ExtendedMemoryIndex
].RangeLength
-= MemoryMap
[*NumRanges
].RangeLength
;
1259 // Update QuarkNcSoc HSMMCTL register
1261 Register
|= (UINT32
)(((RShiftU64(MemorySize
, 16)) & SMM_START_MASK
) + (SMM_WRITE_OPEN
| SMM_READ_OPEN
| SMM_CODE_RD_OPEN
));
1262 QncHsmmcWrite (Register
);
1266 // Chipset only supports cacheable SMRAM
1268 MemoryMap
[*NumRanges
].Type
= DualChannelDdrSmramCacheable
;
1274 // trim 64K memory from highest memory range for Rmu Main binary shadow
1276 MemoryMap
[*NumRanges
].RangeLength
= 0x10000;
1277 MemorySize
-= MemoryMap
[*NumRanges
].RangeLength
;
1278 MemoryMap
[*NumRanges
].PhysicalAddress
= MemorySize
;
1279 MemoryMap
[*NumRanges
].CpuAddress
= MemorySize
;
1280 MemoryMap
[ExtendedMemoryIndex
].RangeLength
-= MemoryMap
[*NumRanges
].RangeLength
;
1281 MemoryMap
[*NumRanges
].Type
= DualChannelDdrReservedMemory
;
1289 Routine Description:
1291 Fill in bit masks to specify reserved memory ranges on the Lakeport platform
1297 OptionRomMask - Bit mask specifying memory regions reserved for Legacy option
1300 SmramMask - Bit mask specifying memory regions reserved for SMM use (if any)
1305 IN OUT PEI_MEMORY_RANGE_OPTION_ROM
*OptionRomMask
,
1306 IN OUT PEI_MEMORY_RANGE_SMRAM
*SmramMask
,
1307 IN OUT PEI_MEMORY_RANGE_PCI_MEMORY
*PciMemoryMask
1312 // Choose regions to reserve for Option ROM use
1314 *OptionRomMask
= PEI_MR_OPTION_ROM_NONE
;
1317 // Choose regions to reserve for SMM use (AB/H SEG and TSEG). Size is in 128K blocks
1319 *SmramMask
= PEI_MR_SMRAM_CACHEABLE_MASK
| PEI_MR_SMRAM_TSEG_MASK
| ((PcdGet32(PcdTSegSize
)) >> 17);
1327 GetPlatformMemorySize (
1328 IN EFI_PEI_SERVICES
**PeiServices
,
1329 IN EFI_BOOT_MODE BootMode
,
1330 IN OUT UINT64
*MemorySize
1334 EFI_PEI_READ_ONLY_VARIABLE2_PPI
*Variable
;
1336 EFI_MEMORY_TYPE_INFORMATION MemoryData
[EfiMaxMemoryType
+ 1];
1339 DataSize
= sizeof (MemoryData
);
1341 if (BootMode
== BOOT_IN_RECOVERY_MODE
) {
1344 // // Treat recovery as if variable not found (eg 1st boot).
1346 Status
= EFI_NOT_FOUND
;
1349 Status
= PeiServicesLocatePpi (
1350 &gEfiPeiReadOnlyVariable2PpiGuid
,
1356 ASSERT_EFI_ERROR (Status
);
1358 DataSize
= sizeof (MemoryData
);
1359 Status
= Variable
->GetVariable (
1361 EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME
,
1362 &gEfiMemoryTypeInformationGuid
,
1370 // Accumulate maximum amount of memory needed
1372 if (EFI_ERROR (Status
)) {
1374 // Start with minimum memory
1376 *MemorySize
= PEI_MIN_MEMORY_SIZE
;
1378 for (Index
= 0; Index
< sizeof(mDefaultQncMemoryTypeInformation
) / sizeof (EFI_MEMORY_TYPE_INFORMATION
); Index
++) {
1379 *MemorySize
+= mDefaultQncMemoryTypeInformation
[Index
].NumberOfPages
* EFI_PAGE_SIZE
;
1383 // Build the GUID'd HOB for DXE
1386 &gEfiMemoryTypeInformationGuid
,
1387 mDefaultQncMemoryTypeInformation
,
1388 sizeof(mDefaultQncMemoryTypeInformation
)
1392 // Start with at least PEI_MIN_MEMORY_SIZE pages of memory for the DXE Core and the DXE Stack
1395 *MemorySize
= PEI_MIN_MEMORY_SIZE
;
1396 for (Index
= 0; Index
< DataSize
/ sizeof (EFI_MEMORY_TYPE_INFORMATION
); Index
++) {
1397 DEBUG ((EFI_D_INFO
, "Index %d, Page: %d\n", Index
, MemoryData
[Index
].NumberOfPages
));
1398 *MemorySize
+= MemoryData
[Index
].NumberOfPages
* EFI_PAGE_SIZE
;
1402 // Build the GUID'd HOB for DXE
1405 &gEfiMemoryTypeInformationGuid
,
1418 IN EFI_PEI_SERVICES
**PeiServices
,
1419 IN EFI_PHYSICAL_ADDRESS BeginAddress
,
1420 IN UINT64 MemoryLength
,
1421 IN PEI_MEMORY_TEST_OP Operation
,
1422 OUT EFI_PHYSICAL_ADDRESS
*ErrorAddress
1426 EFI_PHYSICAL_ADDRESS TempAddress
;
1429 TestPattern
= 0x5A5A5A5A;
1433 // Make sure we don't try and test anything above the max physical address range
1435 ASSERT (BeginAddress
+ MemoryLength
< MAX_ADDRESS
);
1437 switch (Operation
) {
1452 // Write the test pattern into memory range
1454 TempAddress
= BeginAddress
;
1455 while (TempAddress
< BeginAddress
+ MemoryLength
) {
1456 (*(UINT32
*) (UINTN
) TempAddress
) = TestPattern
;
1457 TempAddress
+= SpanSize
;
1460 // Read pattern from memory and compare it
1462 TempAddress
= BeginAddress
;
1463 while (TempAddress
< BeginAddress
+ MemoryLength
) {
1464 if ((*(UINT32
*) (UINTN
) TempAddress
) != TestPattern
) {
1465 *ErrorAddress
= TempAddress
;
1466 DEBUG ((EFI_D_ERROR
, "Memory test failed at 0x%x.\n", TempAddress
));
1467 return EFI_DEVICE_ERROR
;
1470 TempAddress
+= SpanSize
;
1479 This function sets up the platform specific IMR protection for the various
1482 @param PeiMemoryBaseAddress Base address of memory allocated for PEI.
1483 @param PeiMemoryLength Length in bytes of the PEI memory (includes ACPI memory).
1484 @param RequiredMemSize Size in bytes of the ACPI/Runtime memory
1486 @return EFI_SUCCESS The function completed successfully.
1487 EFI_ACCESS_DENIED Access to IMRs failed.
1491 SetPlatformImrPolicy (
1492 IN EFI_PHYSICAL_ADDRESS PeiMemoryBaseAddress
,
1493 IN UINT64 PeiMemoryLength
,
1494 IN UINTN RequiredMemSize
1502 // Check what Soc we are running on (read Host bridge DeviceId)
1504 DeviceId
= QNCMmPci16(0, MC_BUS
, MC_DEV
, MC_FUN
, PCI_DEVICE_ID_OFFSET
);
1507 // If any IMR register is locked then we cannot proceed
1509 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)
1511 Register
= QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID
, Index
);
1512 if (Register
& IMR_LOCK
) {
1513 return EFI_ACCESS_DENIED
;
1518 // Add IMR0 protection for the 'PeiMemory'
1521 QUARK_NC_MEMORY_MANAGER_IMR0
,
1522 (UINT32
)(((RShiftU64(PeiMemoryBaseAddress
, 8)) & IMRL_MASK
) | IMR_EN
),
1523 (UINT32
)((RShiftU64((PeiMemoryBaseAddress
+PeiMemoryLength
-RequiredMemSize
+ EFI_PAGES_TO_SIZE(EDKII_DXE_MEM_SIZE_PAGES
-1) - 1), 8)) & IMRL_MASK
),
1524 (UINT32
)(CPU_SNOOP
+ CPU0_NON_SMM
),
1525 (UINT32
)(CPU_SNOOP
+ CPU0_NON_SMM
)
1529 // Add IMR2 protection for shadowed RMU binary.
1532 QUARK_NC_MEMORY_MANAGER_IMR2
,
1533 (UINT32
)(((RShiftU64((PeiMemoryBaseAddress
+PeiMemoryLength
), 8)) & IMRH_MASK
) | IMR_EN
),
1534 (UINT32
)((RShiftU64((PeiMemoryBaseAddress
+PeiMemoryLength
+PcdGet32(PcdFlashQNCMicrocodeSize
)-1), 8)) & IMRH_MASK
),
1535 (UINT32
)(CPU_SNOOP
+ RMU
+ CPU0_NON_SMM
),
1536 (UINT32
)(CPU_SNOOP
+ RMU
+ CPU0_NON_SMM
)
1540 // Add IMR3 protection for the default SMRAM.
1543 QUARK_NC_MEMORY_MANAGER_IMR3
,
1544 (UINT32
)(((RShiftU64((SMM_DEFAULT_SMBASE
), 8)) & IMRL_MASK
) | IMR_EN
),
1545 (UINT32
)((RShiftU64((SMM_DEFAULT_SMBASE
+SMM_DEFAULT_SMBASE_SIZE_BYTES
-1), 8)) & IMRH_MASK
),
1546 (UINT32
)(CPU_SNOOP
+ CPU0_NON_SMM
),
1547 (UINT32
)(CPU_SNOOP
+ CPU0_NON_SMM
)
1551 // Add IMR5 protection for the legacy S3 and AP Startup Vector region (below 1MB).
1554 QUARK_NC_MEMORY_MANAGER_IMR5
,
1555 (UINT32
)(((RShiftU64(AP_STARTUP_VECTOR
, 8)) & IMRL_MASK
) | IMR_EN
),
1556 (UINT32
)((RShiftU64((AP_STARTUP_VECTOR
+ EFI_PAGE_SIZE
- 1), 8)) & IMRH_MASK
),
1557 (UINT32
)(CPU_SNOOP
+ CPU0_NON_SMM
),
1558 (UINT32
)(CPU_SNOOP
+ CPU0_NON_SMM
)
1562 // Add IMR6 protection for the ACPI Reclaim/ACPI/Runtime Services.
1565 QUARK_NC_MEMORY_MANAGER_IMR6
,
1566 (UINT32
)(((RShiftU64((PeiMemoryBaseAddress
+PeiMemoryLength
-RequiredMemSize
+EFI_PAGES_TO_SIZE(EDKII_DXE_MEM_SIZE_PAGES
-1)), 8)) & IMRL_MASK
) | IMR_EN
),
1567 (UINT32
)((RShiftU64((PeiMemoryBaseAddress
+PeiMemoryLength
-EFI_PAGE_SIZE
-1), 8)) & IMRH_MASK
),
1568 (UINT32
)(CPU_SNOOP
+ CPU0_NON_SMM
),
1569 (UINT32
)(CPU_SNOOP
+ CPU0_NON_SMM
)
1573 // Enable IMR4 protection of eSRAM.
1576 QUARK_NC_MEMORY_MANAGER_IMR4
,
1577 (UINT32
)(((RShiftU64((UINTN
)PcdGet32 (PcdEsramStage1Base
), 8)) & IMRL_MASK
) | IMR_EN
),
1578 (UINT32
)((RShiftU64(((UINTN
)PcdGet32 (PcdEsramStage1Base
) + (UINTN
)PcdGet32 (PcdESramMemorySize
) - 1), 8)) & IMRH_MASK
),
1579 (UINT32
)(CPU_SNOOP
+ CPU0_NON_SMM
),
1580 (UINT32
)(CPU_SNOOP
+ CPU0_NON_SMM
)
1584 // Enable Interrupt on IMR/SMM Violation
1586 QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID
, QUARK_NC_MEMORY_MANAGER_BIMRVCTL
, (UINT32
)(EnableIMRInt
));
1587 if (DeviceId
== QUARK2_MC_DEVICE_ID
) {
1588 QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID
, QUARK_NC_MEMORY_MANAGER_BSMMVCTL
, (UINT32
)(EnableSMMInt
));
1592 // Disable IMR7 memory protection (eSRAM + DDR3 memory) since our policies
1596 QUARK_NC_MEMORY_MANAGER_IMR7
,
1597 (UINT32
)(IMRL_RESET
& ~IMR_EN
),
1599 (UINT32
)IMRX_ALL_ACCESS
,
1600 (UINT32
)IMRX_ALL_ACCESS
1606 /** Return info derived from Installing Memory by MemoryInit.
1608 @param[out] RmuMainBaseAddressPtr Return RmuMainBaseAddress to this location.
1609 @param[out] SmramDescriptorPtr Return start of Smram descriptor list to this location.
1610 @param[out] NumSmramRegionsPtr Return numbers of Smram regions to this location.
1612 @return Address of RMU shadow region at the top of available memory.
1613 @return List of Smram descriptors for each Smram region.
1614 @return Numbers of Smram regions.
1618 InfoPostInstallMemory (
1619 OUT UINT32
*RmuMainBaseAddressPtr OPTIONAL
,
1620 OUT EFI_SMRAM_DESCRIPTOR
**SmramDescriptorPtr OPTIONAL
,
1621 OUT UINTN
*NumSmramRegionsPtr OPTIONAL
1625 EFI_PEI_HOB_POINTERS Hob
;
1627 EFI_SMRAM_HOB_DESCRIPTOR_BLOCK
*SmramHobDescriptorBlock
;
1629 if ((RmuMainBaseAddressPtr
== NULL
) && (SmramDescriptorPtr
== NULL
) && (NumSmramRegionsPtr
== NULL
)) {
1633 SmramHobDescriptorBlock
= NULL
;
1634 if (SmramDescriptorPtr
!= NULL
) {
1635 *SmramDescriptorPtr
= NULL
;
1637 if (NumSmramRegionsPtr
!= NULL
) {
1638 *NumSmramRegionsPtr
= 0;
1642 // Calculate RMU shadow region base address.
1643 // Set to 1 MB. Since 1MB cacheability will always be set
1644 // until override by CSM.
1646 CalcLength
= 0x100000;
1648 Status
= PeiServicesGetHobList ((VOID
**) &Hob
.Raw
);
1649 ASSERT_EFI_ERROR (Status
);
1650 while (!END_OF_HOB_LIST (Hob
)) {
1651 if (Hob
.Header
->HobType
== EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
) {
1652 if (Hob
.ResourceDescriptor
->ResourceType
== EFI_RESOURCE_SYSTEM_MEMORY
) {
1654 // Skip the memory region below 1MB
1656 if (Hob
.ResourceDescriptor
->PhysicalStart
>= 0x100000) {
1657 CalcLength
+= (UINT64
) (Hob
.ResourceDescriptor
->ResourceLength
);
1660 } else if (Hob
.Header
->HobType
== EFI_HOB_TYPE_GUID_EXTENSION
) {
1661 if (CompareGuid (&(Hob
.Guid
->Name
), &gEfiSmmPeiSmramMemoryReserveGuid
)) {
1662 SmramHobDescriptorBlock
= (VOID
*) (Hob
.Raw
+ sizeof (EFI_HOB_GUID_TYPE
));
1663 if (SmramDescriptorPtr
!= NULL
) {
1664 *SmramDescriptorPtr
= SmramHobDescriptorBlock
->Descriptor
;
1666 if (NumSmramRegionsPtr
!= NULL
) {
1667 *NumSmramRegionsPtr
= SmramHobDescriptorBlock
->NumberOfSmmReservedRegions
;
1671 Hob
.Raw
= GET_NEXT_HOB (Hob
);
1674 if (RmuMainBaseAddressPtr
!= NULL
) {
1675 *RmuMainBaseAddressPtr
= (UINT32
) CalcLength
;