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