6b07d7829328b5abed4d47679ece7b3f9585d7e1
[mirror_edk2.git] / QuarkPlatformPkg / Platform / Pei / PlatformInit / MrcWrapper.c
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 UINTN RequiredMemSize;
558 EFI_RESOURCE_ATTRIBUTE_TYPE Attribute;
559 EFI_PHYSICAL_ADDRESS BadMemoryAddress;
560 EFI_SMRAM_DESCRIPTOR DescriptorAcpiVariable;
561 VOID *CapsuleBuffer;
562 UINTN CapsuleBufferLength;
563 PEI_CAPSULE_PPI *Capsule;
564 VOID *LargeMemRangeBuf;
565 UINTN LargeMemRangeBufLen;
566 UINT8 MorControl;
567 UINTN DataSize;
568
569 //
570 // Test the memory from 1M->TOM
571 //
572 if (BootMode != BOOT_ON_FLASH_UPDATE) {
573 Status = BaseMemoryTest (
574 PeiServices,
575 0x100000,
576 (TotalMemorySize - 0x100000),
577 Quick,
578 &BadMemoryAddress
579 );
580 ASSERT_EFI_ERROR (Status);
581 }
582
583
584 //
585 // Get the Memory Map
586 //
587 NumRanges = MAX_RANGES;
588
589 ZeroMem (MemoryMap, sizeof (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE) * NumRanges);
590
591 Status = GetMemoryMap (
592 PeiServices,
593 TotalMemorySize,
594 (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE *) MemoryMap,
595 &NumRanges
596 );
597 ASSERT_EFI_ERROR (Status);
598
599 //
600 // Find the highest memory range in processor native address space to give to
601 // PEI. Then take the top.
602 //
603 PeiMemoryBaseAddress = 0;
604
605 //
606 // Query the platform for the minimum memory size
607 //
608
609 Status = GetPlatformMemorySize (
610 PeiServices,
611 BootMode,
612 &PeiMemoryLength
613 );
614 ASSERT_EFI_ERROR (Status);
615
616 //
617 // Get required memory size for ACPI use. This helps to put ACPI memory on the topest
618 //
619 RequiredMemSize = 0;
620 RetriveRequiredMemorySize (PeiServices, &RequiredMemSize);
621
622 //
623 // Detect MOR request by the OS.
624 //
625 MorControl = 0;
626 DataSize = sizeof (MorControl);
627 Status = VariableServices->GetVariable (
628 VariableServices,
629 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
630 &gEfiMemoryOverwriteControlDataGuid,
631 NULL,
632 &DataSize,
633 &MorControl
634 );
635
636 PeiMemoryIndex = 0;
637
638 for (Index = 0; Index < NumRanges; Index++)
639 {
640 DEBUG ((EFI_D_INFO, "Found 0x%x bytes at ", MemoryMap[Index].RangeLength));
641 DEBUG ((EFI_D_INFO, "0x%x.\n", MemoryMap[Index].PhysicalAddress));
642
643 //
644 // If OS requested a memory overwrite perform it now. Only do it for memory
645 // used by the OS.
646 //
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) {
651 //
652 // ZeroMem() generates an ASSERT() if Buffer parameter is NULL.
653 // Clear byte at 0 and start clear operation at address 1.
654 //
655 *(UINT8 *)(0) = 0;
656 ZeroMem ((VOID *)1, (UINTN)MemoryMap[Index].RangeLength - 1);
657 } else {
658 ZeroMem (
659 (VOID *)(UINTN)MemoryMap[Index].PhysicalAddress,
660 (UINTN)MemoryMap[Index].RangeLength
661 );
662 }
663 }
664 }
665
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 -
672 PeiMemoryLength;
673 PeiMemoryIndex = Index;
674 }
675 }
676
677 //
678 // Find the largest memory range excluding that given to PEI.
679 //
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;
689 }
690 } else {
691 if ((MemoryMap[Index].RangeLength - PeiMemoryLength) >= LargeMemRangeBufLen) {
692 LargeMemRangeBuf = (VOID *) ((UINTN) MemoryMap[Index].PhysicalAddress);
693 LargeMemRangeBufLen = (UINTN) (MemoryMap[Index].RangeLength - PeiMemoryLength);
694 }
695 }
696 }
697 }
698
699 Capsule = NULL;
700 CapsuleBuffer = NULL;
701 CapsuleBufferLength = 0;
702 if (BootMode == BOOT_ON_FLASH_UPDATE) {
703 Status = PeiServicesLocatePpi (
704 &gPeiCapsulePpiGuid, // GUID
705 0, // INSTANCE
706 NULL, // EFI_PEI_PPI_DESCRIPTOR
707 (VOID **)&Capsule // PPI
708 );
709 ASSERT_EFI_ERROR (Status);
710
711 if (Status == EFI_SUCCESS) {
712 CapsuleBuffer = LargeMemRangeBuf;
713 CapsuleBufferLength = LargeMemRangeBufLen;
714
715 //
716 // Call the Capsule PPI Coalesce function to coalesce the capsule data.
717 //
718 Status = Capsule->Coalesce (
719 PeiServices,
720 &CapsuleBuffer,
721 &CapsuleBufferLength
722 );
723 //
724 // If it failed, then NULL out our capsule PPI pointer so that the capsule
725 // HOB does not get created below.
726 //
727 if (Status != EFI_SUCCESS) {
728 Capsule = NULL;
729 }
730 }
731 }
732
733 //
734 // Set up the IMR policy required for this platform
735 //
736 Status = SetPlatformImrPolicy (
737 PeiMemoryBaseAddress,
738 PeiMemoryLength,
739 RequiredMemSize
740 );
741 ASSERT_EFI_ERROR (Status);
742
743 //
744 // Carve out the top memory reserved for ACPI
745 //
746 Status = PeiServicesInstallPeiMemory (PeiMemoryBaseAddress, (PeiMemoryLength - RequiredMemSize));
747 ASSERT_EFI_ERROR (Status);
748
749 BuildResourceDescriptorHob (
750 EFI_RESOURCE_SYSTEM_MEMORY, // MemoryType,
751 (
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
759 ),
760 PeiMemoryBaseAddress, // MemoryBegin
761 PeiMemoryLength // MemoryLength
762 );
763
764 //
765 // Install physical memory descriptor hobs for each memory range.
766 //
767 SmramRanges = 0;
768 for (Index = 0; Index < NumRanges; Index++) {
769 Attribute = 0;
770 if (MemoryMap[Index].Type == DualChannelDdrMainMemory)
771 {
772 if (Index == PeiMemoryIndex) {
773 //
774 // This is a partially tested Main Memory range, give it to EFI
775 //
776 BuildResourceDescriptorHob (
777 EFI_RESOURCE_SYSTEM_MEMORY,
778 (
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
785 ),
786 MemoryMap[Index].PhysicalAddress,
787 MemoryMap[Index].RangeLength - PeiMemoryLength
788 );
789 } else {
790 //
791 // This is an untested Main Memory range, give it to EFI
792 //
793 BuildResourceDescriptorHob (
794 EFI_RESOURCE_SYSTEM_MEMORY, // MemoryType,
795 (
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
802 ),
803 MemoryMap[Index].PhysicalAddress, // MemoryBegin
804 MemoryMap[Index].RangeLength // MemoryLength
805 );
806 }
807 } else {
808 if ((MemoryMap[Index].Type == DualChannelDdrSmramCacheable) ||
809 (MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable)) {
810 SmramRanges++;
811 }
812 if ((MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable) ||
813 (MemoryMap[Index].Type == DualChannelDdrGraphicsMemoryNonCacheable)) {
814 Attribute |= EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE;
815 }
816 if ((MemoryMap[Index].Type == DualChannelDdrSmramCacheable) ||
817 (MemoryMap[Index].Type == DualChannelDdrGraphicsMemoryCacheable)) {
818 //
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.
825 //
826 Attribute |= EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE | EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE;
827 }
828 if (MemoryMap[Index].Type == DualChannelDdrReservedMemory) {
829 Attribute |= EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
830 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE;
831 }
832 //
833 // Make sure non-system memory is marked as reserved
834 //
835 BuildResourceDescriptorHob (
836 EFI_RESOURCE_MEMORY_RESERVED, // MemoryType,
837 Attribute, // MemoryAttribute
838 MemoryMap[Index].PhysicalAddress, // MemoryBegin
839 MemoryMap[Index].RangeLength // MemoryLength
840 );
841 }
842 }
843
844 //
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
847 //
848 ASSERT (SmramRanges > 0);
849 BufferSize = sizeof (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK);
850 BufferSize += ((SmramRanges - 1) * sizeof (EFI_SMRAM_DESCRIPTOR));
851
852 Hob.Raw = BuildGuidHob (
853 &gEfiSmmPeiSmramMemoryReserveGuid,
854 BufferSize
855 );
856 ASSERT (Hob.Raw);
857
858 SmramHobDescriptorBlock = (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *) (Hob.Raw);
859 SmramHobDescriptorBlock->NumberOfSmmReservedRegions = SmramRanges;
860
861 SmramIndex = 0;
862 for (Index = 0; Index < NumRanges; Index++) {
863 if ((MemoryMap[Index].Type == DualChannelDdrSmramCacheable) ||
864 (MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable)
865 ) {
866 //
867 // This is an SMRAM range, create an SMRAM descriptor
868 //
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;
874 } else {
875 SmramHobDescriptorBlock->Descriptor[SmramIndex].RegionState = EFI_SMRAM_CLOSED;
876 }
877
878 SmramIndex++;
879 }
880 }
881
882 //
883 // Build a HOB with the location of the reserved memory range.
884 //
885 CopyMem(&DescriptorAcpiVariable, &SmramHobDescriptorBlock->Descriptor[SmramRanges-1], sizeof(EFI_SMRAM_DESCRIPTOR));
886 DescriptorAcpiVariable.CpuStart += RESERVED_CPU_S3_SAVE_OFFSET;
887 BuildGuidDataHob (
888 &gEfiAcpiVariableGuid,
889 &DescriptorAcpiVariable,
890 sizeof (EFI_SMRAM_DESCRIPTOR)
891 );
892
893 //
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.
896 //
897 if (Capsule != NULL) {
898 Status = Capsule->CreateState (PeiServices, CapsuleBuffer, CapsuleBufferLength);
899 }
900
901 return EFI_SUCCESS;
902 }
903
904 /**
905
906 Find memory that is reserved so PEI has some to use.
907
908 @param PeiServices PEI Services table.
909 @param VariableSevices Variable PPI instance.
910
911 @return EFI_SUCCESS The function completed successfully.
912 Error value from LocatePpi()
913 Error Value from VariableServices->GetVariable()
914
915 **/
916 EFI_STATUS
917 InstallS3Memory (
918 IN EFI_PEI_SERVICES **PeiServices,
919 IN EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariableServices,
920 IN UINT32 TotalMemorySize
921 )
922 {
923 EFI_STATUS Status;
924 UINTN S3MemoryBase;
925 UINTN S3MemorySize;
926 UINT8 SmramRanges;
927 UINT8 NumRanges;
928 UINT8 Index;
929 UINT8 SmramIndex;
930 UINTN BufferSize;
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;
936
937 //
938 // Get the Memory Map
939 //
940 NumRanges = MAX_RANGES;
941
942 ZeroMem (MemoryMap, sizeof (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE) * NumRanges);
943
944 Status = GetMemoryMap (
945 PeiServices,
946 TotalMemorySize,
947 (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE *) MemoryMap,
948 &NumRanges
949 );
950 ASSERT_EFI_ERROR (Status);
951
952 //
953 // Install physical memory descriptor hobs for each memory range.
954 //
955 SmramRanges = 0;
956 for (Index = 0; Index < NumRanges; Index++) {
957 if ((MemoryMap[Index].Type == DualChannelDdrSmramCacheable) ||
958 (MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable)) {
959 SmramRanges++;
960 }
961 }
962
963 ASSERT (SmramRanges > 0);
964
965 //
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
968 //
969 BufferSize = sizeof (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK);
970 if (SmramRanges > 0) {
971 BufferSize += ((SmramRanges - 1) * sizeof (EFI_SMRAM_DESCRIPTOR));
972 }
973
974 Hob.Raw = BuildGuidHob (
975 &gEfiSmmPeiSmramMemoryReserveGuid,
976 BufferSize
977 );
978 ASSERT (Hob.Raw);
979
980 SmramHobDescriptorBlock = (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *) (Hob.Raw);
981 SmramHobDescriptorBlock->NumberOfSmmReservedRegions = SmramRanges;
982
983 SmramIndex = 0;
984 for (Index = 0; Index < NumRanges; Index++) {
985 if ((MemoryMap[Index].Type == DualChannelDdrSmramCacheable) ||
986 (MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable)
987 ) {
988 //
989 // This is an SMRAM range, create an SMRAM descriptor
990 //
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;
996 } else {
997 SmramHobDescriptorBlock->Descriptor[SmramIndex].RegionState = EFI_SMRAM_CLOSED;
998 }
999
1000 SmramIndex++;
1001 }
1002 }
1003
1004 //
1005 // Build a HOB with the location of the reserved memory range.
1006 //
1007 CopyMem(&DescriptorAcpiVariable, &SmramHobDescriptorBlock->Descriptor[SmramRanges-1], sizeof(EFI_SMRAM_DESCRIPTOR));
1008 DescriptorAcpiVariable.CpuStart += RESERVED_CPU_S3_SAVE_OFFSET;
1009 BuildGuidDataHob (
1010 &gEfiAcpiVariableGuid,
1011 &DescriptorAcpiVariable,
1012 sizeof (EFI_SMRAM_DESCRIPTOR)
1013 );
1014
1015 //
1016 // Get the location and size of the S3 memory range in the reserved page and
1017 // install it as PEI Memory.
1018 //
1019
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);
1023
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));
1028
1029 Status = PeiServicesInstallPeiMemory (S3MemoryBase, S3MemorySize);
1030 ASSERT_EFI_ERROR (Status);
1031
1032 //
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.
1036 //
1037 ASSERT ((S3MemoryRangeData->SystemMemoryLength - 0x100000) > 0);
1038 BuildResourceDescriptorHob (
1039 EFI_RESOURCE_SYSTEM_MEMORY,
1040 (
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
1047 ),
1048 0x100000,
1049 S3MemoryRangeData->SystemMemoryLength - 0x100000
1050 );
1051
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,
1057 (
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
1064 ),
1065 MemoryMap[Index].PhysicalAddress,
1066 MemoryMap[Index].RangeLength
1067 );
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));
1070 }
1071 }
1072
1073 return EFI_SUCCESS;
1074 }
1075
1076 /**
1077
1078 This function returns the size, in bytes, required for the DXE phase.
1079
1080 @param PeiServices PEI Services table.
1081 @param Size Pointer to the size, in bytes, required for the DXE phase.
1082
1083 @return None
1084
1085 **/
1086 VOID
1087 RetriveRequiredMemorySize (
1088 IN EFI_PEI_SERVICES **PeiServices,
1089 OUT UINTN *Size
1090 )
1091 {
1092 EFI_PEI_HOB_POINTERS Hob;
1093 EFI_MEMORY_TYPE_INFORMATION *MemoryData;
1094 UINT8 Index;
1095 UINTN TempPageNum;
1096
1097 MemoryData = NULL;
1098 TempPageNum = 0;
1099 Index = 0;
1100
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)
1105 ) {
1106 MemoryData = (EFI_MEMORY_TYPE_INFORMATION *) (Hob.Raw + sizeof (EFI_HOB_GENERIC_HEADER) + sizeof (EFI_GUID));
1107 break;
1108 }
1109
1110 Hob.Raw = GET_NEXT_HOB (Hob);
1111 }
1112 //
1113 // Platform PEIM should supply such a information. Generic PEIM doesn't assume any default value
1114 //
1115 if (!MemoryData) {
1116 return ;
1117 }
1118
1119 while (MemoryData[Index].Type != EfiMaxMemoryType) {
1120 //
1121 // Accumulate default memory size requirements
1122 //
1123 TempPageNum += MemoryData[Index].NumberOfPages;
1124 Index++;
1125 }
1126
1127 if (TempPageNum == 0) {
1128 return ;
1129 }
1130
1131 //
1132 // Add additional pages used by DXE memory manager
1133 //
1134 (*Size) = (TempPageNum + EDKII_DXE_MEM_SIZE_PAGES) * EFI_PAGE_SIZE;
1135
1136 return ;
1137 }
1138
1139 /**
1140
1141 This function returns the memory ranges to be enabled, along with information
1142 describing how the range should be used.
1143
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.
1151
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.
1155
1156 **/
1157 EFI_STATUS
1158 GetMemoryMap (
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
1163 )
1164 {
1165 EFI_PHYSICAL_ADDRESS MemorySize;
1166 EFI_PHYSICAL_ADDRESS RowLength;
1167 EFI_STATUS Status;
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;
1172 UINT32 BlockNum;
1173 UINT8 ExtendedMemoryIndex;
1174 UINT32 Register;
1175
1176 if ((*NumRanges) < MAX_RANGES) {
1177 return EFI_BUFFER_TOO_SMALL;
1178 }
1179
1180 *NumRanges = 0;
1181
1182 //
1183 // Find out which memory ranges to reserve on this platform
1184 //
1185 Status = ChooseRanges (
1186 &OptionRomMask,
1187 &SmramMask,
1188 &PciMemoryMask
1189 );
1190 ASSERT_EFI_ERROR (Status);
1191
1192 //
1193 // Generate Memory ranges for the memory map.
1194 //
1195 MemorySize = 0;
1196
1197 RowLength = TotalMemorySize;
1198
1199 //
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
1202 //
1203 MemoryMap[*NumRanges].PhysicalAddress = MemorySize;
1204 MemoryMap[*NumRanges].CpuAddress = MemorySize;
1205 MemoryMap[*NumRanges].RangeLength = 0xA0000;
1206 MemoryMap[*NumRanges].Type = DualChannelDdrMainMemory;
1207 (*NumRanges)++;
1208
1209 //
1210 // Just mark this range reserved
1211 //
1212 MemoryMap[*NumRanges].PhysicalAddress = 0xA0000;
1213 MemoryMap[*NumRanges].CpuAddress = 0xA0000;
1214 MemoryMap[*NumRanges].RangeLength = 0x60000;
1215 MemoryMap[*NumRanges].Type = DualChannelDdrReservedMemory;
1216 (*NumRanges)++;
1217
1218 RowLength -= (0x100000 - MemorySize);
1219 MemorySize = 0x100000;
1220
1221 //
1222 // Add remaining memory to the memory map
1223 //
1224 MemoryMap[*NumRanges].PhysicalAddress = MemorySize;
1225 MemoryMap[*NumRanges].CpuAddress = MemorySize;
1226 MemoryMap[*NumRanges].RangeLength = RowLength;
1227 MemoryMap[*NumRanges].Type = DualChannelDdrMainMemory;
1228 (*NumRanges)++;
1229 MemorySize += RowLength;
1230
1231 ExtendedMemoryIndex = (UINT8) (*NumRanges - 1);
1232
1233 // See if we need to trim TSEG out of the highest memory range
1234 //
1235 if (SmramMask & PEI_MR_SMRAM_TSEG_MASK) {//pcd
1236 //
1237 // Create the new range for TSEG and remove that range from the previous SdrDdrMainMemory range
1238 //
1239 TsegMask = (SmramMask & PEI_MR_SMRAM_SIZE_MASK);
1240
1241 BlockNum = 1;
1242 while (TsegMask) {
1243 TsegMask >>= 1;
1244 BlockNum <<= 1;
1245 }
1246
1247 BlockNum >>= 1;
1248
1249 if (BlockNum) {
1250
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;
1257
1258 //
1259 // Update QuarkNcSoc HSMMCTL register
1260 //
1261 Register |= (UINT32)(((RShiftU64(MemorySize, 16)) & SMM_START_MASK) + (SMM_WRITE_OPEN | SMM_READ_OPEN | SMM_CODE_RD_OPEN));
1262 QncHsmmcWrite (Register);
1263 }
1264
1265 //
1266 // Chipset only supports cacheable SMRAM
1267 //
1268 MemoryMap[*NumRanges].Type = DualChannelDdrSmramCacheable;
1269
1270 (*NumRanges)++;
1271 }
1272
1273 //
1274 // trim 64K memory from highest memory range for Rmu Main binary shadow
1275 //
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;
1282 (*NumRanges)++;
1283
1284 return EFI_SUCCESS;
1285 }
1286
1287 /**
1288
1289 Routine Description:
1290
1291 Fill in bit masks to specify reserved memory ranges on the Lakeport platform
1292
1293 Arguments:
1294
1295 Returns:
1296
1297 OptionRomMask - Bit mask specifying memory regions reserved for Legacy option
1298 ROM use (if any)
1299
1300 SmramMask - Bit mask specifying memory regions reserved for SMM use (if any)
1301
1302 **/
1303 EFI_STATUS
1304 ChooseRanges (
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
1308 )
1309 {
1310
1311 //
1312 // Choose regions to reserve for Option ROM use
1313 //
1314 *OptionRomMask = PEI_MR_OPTION_ROM_NONE;
1315
1316 //
1317 // Choose regions to reserve for SMM use (AB/H SEG and TSEG). Size is in 128K blocks
1318 //
1319 *SmramMask = PEI_MR_SMRAM_CACHEABLE_MASK | PEI_MR_SMRAM_TSEG_MASK | ((PcdGet32(PcdTSegSize)) >> 17);
1320
1321 *PciMemoryMask = 0;
1322
1323 return EFI_SUCCESS;
1324 }
1325
1326 EFI_STATUS
1327 GetPlatformMemorySize (
1328 IN EFI_PEI_SERVICES **PeiServices,
1329 IN EFI_BOOT_MODE BootMode,
1330 IN OUT UINT64 *MemorySize
1331 )
1332 {
1333 EFI_STATUS Status;
1334 EFI_PEI_READ_ONLY_VARIABLE2_PPI *Variable;
1335 UINTN DataSize;
1336 EFI_MEMORY_TYPE_INFORMATION MemoryData [EfiMaxMemoryType + 1];
1337 UINTN Index;
1338
1339 DataSize = sizeof (MemoryData);
1340
1341 if (BootMode == BOOT_IN_RECOVERY_MODE) {
1342
1343 //
1344 // // Treat recovery as if variable not found (eg 1st boot).
1345 //
1346 Status = EFI_NOT_FOUND;
1347
1348 } else {
1349 Status = PeiServicesLocatePpi (
1350 &gEfiPeiReadOnlyVariable2PpiGuid,
1351 0,
1352 NULL,
1353 (VOID **)&Variable
1354 );
1355
1356 ASSERT_EFI_ERROR (Status);
1357
1358 DataSize = sizeof (MemoryData);
1359 Status = Variable->GetVariable (
1360 Variable,
1361 EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
1362 &gEfiMemoryTypeInformationGuid,
1363 NULL,
1364 &DataSize,
1365 &MemoryData
1366 );
1367 }
1368
1369 //
1370 // Accumulate maximum amount of memory needed
1371 //
1372 if (EFI_ERROR (Status)) {
1373 //
1374 // Start with minimum memory
1375 //
1376 *MemorySize = PEI_MIN_MEMORY_SIZE;
1377
1378 for (Index = 0; Index < sizeof(mDefaultQncMemoryTypeInformation) / sizeof (EFI_MEMORY_TYPE_INFORMATION); Index++) {
1379 *MemorySize += mDefaultQncMemoryTypeInformation[Index].NumberOfPages * EFI_PAGE_SIZE;
1380 }
1381
1382 //
1383 // Build the GUID'd HOB for DXE
1384 //
1385 BuildGuidDataHob (
1386 &gEfiMemoryTypeInformationGuid,
1387 mDefaultQncMemoryTypeInformation,
1388 sizeof(mDefaultQncMemoryTypeInformation)
1389 );
1390 } else {
1391 //
1392 // Start with at least PEI_MIN_MEMORY_SIZE pages of memory for the DXE Core and the DXE Stack
1393 //
1394
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;
1399 }
1400
1401 //
1402 // Build the GUID'd HOB for DXE
1403 //
1404 BuildGuidDataHob (
1405 &gEfiMemoryTypeInformationGuid,
1406 MemoryData,
1407 DataSize
1408 );
1409
1410 }
1411
1412 return EFI_SUCCESS;
1413 }
1414
1415
1416 EFI_STATUS
1417 BaseMemoryTest (
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
1423 )
1424 {
1425 UINT32 TestPattern;
1426 EFI_PHYSICAL_ADDRESS TempAddress;
1427 UINT32 SpanSize;
1428
1429 TestPattern = 0x5A5A5A5A;
1430 SpanSize = 0;
1431
1432 //
1433 // Make sure we don't try and test anything above the max physical address range
1434 //
1435 ASSERT (BeginAddress + MemoryLength < MAX_ADDRESS);
1436
1437 switch (Operation) {
1438 case Extensive:
1439 SpanSize = 0x4;
1440 break;
1441
1442 case Sparse:
1443 case Quick:
1444 SpanSize = 0x40000;
1445 break;
1446
1447 case Ignore:
1448 goto Done;
1449 break;
1450 }
1451 //
1452 // Write the test pattern into memory range
1453 //
1454 TempAddress = BeginAddress;
1455 while (TempAddress < BeginAddress + MemoryLength) {
1456 (*(UINT32 *) (UINTN) TempAddress) = TestPattern;
1457 TempAddress += SpanSize;
1458 }
1459 //
1460 // Read pattern from memory and compare it
1461 //
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;
1468 }
1469
1470 TempAddress += SpanSize;
1471 }
1472
1473 Done:
1474 return EFI_SUCCESS;
1475 }
1476
1477 /**
1478
1479 This function sets up the platform specific IMR protection for the various
1480 memory regions.
1481
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
1485
1486 @return EFI_SUCCESS The function completed successfully.
1487 EFI_ACCESS_DENIED Access to IMRs failed.
1488
1489 **/
1490 EFI_STATUS
1491 SetPlatformImrPolicy (
1492 IN EFI_PHYSICAL_ADDRESS PeiMemoryBaseAddress,
1493 IN UINT64 PeiMemoryLength,
1494 IN UINTN RequiredMemSize
1495 )
1496 {
1497 UINT8 Index;
1498 UINT32 Register;
1499 UINT16 DeviceId;
1500
1501 //
1502 // Check what Soc we are running on (read Host bridge DeviceId)
1503 //
1504 DeviceId = QNCMmPci16(0, MC_BUS, MC_DEV, MC_FUN, PCI_DEVICE_ID_OFFSET);
1505
1506 //
1507 // If any IMR register is locked then we cannot proceed
1508 //
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)
1510 {
1511 Register = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, Index);
1512 if (Register & IMR_LOCK) {
1513 return EFI_ACCESS_DENIED;
1514 }
1515 }
1516
1517 //
1518 // Add IMR0 protection for the 'PeiMemory'
1519 //
1520 QncImrWrite (
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)
1526 );
1527
1528 //
1529 // Add IMR2 protection for shadowed RMU binary.
1530 //
1531 QncImrWrite (
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)
1537 );
1538
1539 //
1540 // Add IMR3 protection for the default SMRAM.
1541 //
1542 QncImrWrite (
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)
1548 );
1549
1550 //
1551 // Add IMR5 protection for the legacy S3 and AP Startup Vector region (below 1MB).
1552 //
1553 QncImrWrite (
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)
1559 );
1560
1561 //
1562 // Add IMR6 protection for the ACPI Reclaim/ACPI/Runtime Services.
1563 //
1564 QncImrWrite (
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)
1570 );
1571
1572 //
1573 // Enable IMR4 protection of eSRAM.
1574 //
1575 QncImrWrite (
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)
1581 );
1582
1583 //
1584 // Enable Interrupt on IMR/SMM Violation
1585 //
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));
1589 }
1590
1591 //
1592 // Disable IMR7 memory protection (eSRAM + DDR3 memory) since our policies
1593 // are now setup.
1594 //
1595 QncImrWrite (
1596 QUARK_NC_MEMORY_MANAGER_IMR7,
1597 (UINT32)(IMRL_RESET & ~IMR_EN),
1598 (UINT32)IMRH_RESET,
1599 (UINT32)IMRX_ALL_ACCESS,
1600 (UINT32)IMRX_ALL_ACCESS
1601 );
1602
1603 return EFI_SUCCESS;
1604 }
1605
1606 /** Return info derived from Installing Memory by MemoryInit.
1607
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.
1611
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.
1615 **/
1616 VOID
1617 EFIAPI
1618 InfoPostInstallMemory (
1619 OUT UINT32 *RmuMainBaseAddressPtr OPTIONAL,
1620 OUT EFI_SMRAM_DESCRIPTOR **SmramDescriptorPtr OPTIONAL,
1621 OUT UINTN *NumSmramRegionsPtr OPTIONAL
1622 )
1623 {
1624 EFI_STATUS Status;
1625 EFI_PEI_HOB_POINTERS Hob;
1626 UINT64 CalcLength;
1627 EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *SmramHobDescriptorBlock;
1628
1629 if ((RmuMainBaseAddressPtr == NULL) && (SmramDescriptorPtr == NULL) && (NumSmramRegionsPtr == NULL)) {
1630 return;
1631 }
1632
1633 SmramHobDescriptorBlock = NULL;
1634 if (SmramDescriptorPtr != NULL) {
1635 *SmramDescriptorPtr = NULL;
1636 }
1637 if (NumSmramRegionsPtr != NULL) {
1638 *NumSmramRegionsPtr = 0;
1639 }
1640
1641 //
1642 // Calculate RMU shadow region base address.
1643 // Set to 1 MB. Since 1MB cacheability will always be set
1644 // until override by CSM.
1645 //
1646 CalcLength = 0x100000;
1647
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) {
1653 //
1654 // Skip the memory region below 1MB
1655 //
1656 if (Hob.ResourceDescriptor->PhysicalStart >= 0x100000) {
1657 CalcLength += (UINT64) (Hob.ResourceDescriptor->ResourceLength);
1658 }
1659 }
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;
1665 }
1666 if (NumSmramRegionsPtr != NULL) {
1667 *NumSmramRegionsPtr = SmramHobDescriptorBlock->NumberOfSmmReservedRegions;
1668 }
1669 }
1670 }
1671 Hob.Raw = GET_NEXT_HOB (Hob);
1672 }
1673
1674 if (RmuMainBaseAddressPtr != NULL) {
1675 *RmuMainBaseAddressPtr = (UINT32) CalcLength;
1676 }
1677 }