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