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