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