]>
Commit | Line | Data |
---|---|---|
b303605e MK |
1 | /** @file\r |
2 | Framework PEIM to initialize memory on a Quark Memory Controller.\r | |
3 | \r | |
a9054761 | 4 | Copyright (c) 2013 - 2016, Intel Corporation.\r |
b303605e MK |
5 | \r |
6 | This program and the accompanying materials\r | |
7 | are licensed and made available under the terms and conditions of the BSD License\r | |
8 | which accompanies this distribution. The full text of the license may be found at\r | |
9 | http://opensource.org/licenses/bsd-license.php\r | |
10 | \r | |
11 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r | |
12 | WITHOUT 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 | |
41 | EFI_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 | |
56 | VOID\r | |
57 | MrcUartConfig(\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 | |
81 | EFI_STATUS\r | |
82 | MrcConfigureFromMcFuses (\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 | |
113 | EFI_STATUS\r | |
114 | MrcConfigureFromInfoHob (\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 | |
171 | VOID\r | |
172 | EccScrubSetup(\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 | |
205 | VOID\r | |
206 | PostInstallMemory (\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 | |
256 | EFI_STATUS\r | |
257 | MemoryInit (\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 | |
464 | EFI_STATUS\r | |
465 | SaveConfig (\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 | |
496 | EFI_STATUS\r | |
497 | LoadConfig (\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 | |
537 | EFI_STATUS\r | |
538 | InstallEfiMemory (\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 | |
916 | EFI_STATUS\r | |
917 | InstallS3Memory (\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 | |
1086 | VOID\r | |
1087 | RetriveRequiredMemorySize (\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 | |
1157 | EFI_STATUS\r | |
1158 | GetMemoryMap (\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 | |
1289 | Routine Description:\r | |
1290 | \r | |
1291 | Fill in bit masks to specify reserved memory ranges on the Lakeport platform\r | |
1292 | \r | |
1293 | Arguments:\r | |
1294 | \r | |
1295 | Returns:\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 | |
1303 | EFI_STATUS\r | |
1304 | ChooseRanges (\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 | |
1326 | EFI_STATUS\r | |
1327 | GetPlatformMemorySize (\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 | |
1416 | EFI_STATUS\r | |
1417 | BaseMemoryTest (\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 | |
1473 | Done:\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 | |
1490 | EFI_STATUS\r | |
1491 | SetPlatformImrPolicy (\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 | |
1616 | VOID\r | |
1617 | EFIAPI\r | |
1618 | InfoPostInstallMemory (\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 |