1 /**@file 2 Platform PEI driver 3 4 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR> 5 Copyright (c) 2011, Andrei Warkentin <andreiw (at) motorola.com> 6 7 This program and the accompanying materials 8 are licensed and made available under the terms and conditions of the BSD License 9 which accompanies this distribution. The full text of the license may be found at 10 http://opensource.org/licenses/bsd-license.php 11 12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 14 15 **/ 16 17 // 18 // The package level header files this module uses 19 // 20 #include <PiPei.h> 21 22 // 23 // The Library classes this module consumes 24 // 25 #include <Library/BaseLib.h> 26 #include <Library/DebugLib.h> 27 #include <Library/HobLib.h> 28 #include <Library/IoLib.h> 29 #include <Library/MemoryAllocationLib.h> 30 #include <Library/PcdLib.h> 31 #include <Library/PciLib.h> 32 #include <Library/PeimEntryPoint.h> 33 #include <Library/PeiServicesLib.h> 34 #include <Library/QemuFwCfgLib.h> 35 #include <Library/ResourcePublicationLib.h> 36 #include <Guid/MemoryTypeInformation.h> 37 #include <Ppi/MasterBootMode.h> 38 #include <IndustryStandard/Pci22.h> 39 #include <OvmfPlatforms.h> 40 41 #include "Platform.h" 42 #include "Cmos.h" 43 44 EFI_MEMORY_TYPE_INFORMATION mDefaultMemoryTypeInformation[] = { 45 { EfiACPIMemoryNVS, 0x004 }, 46 { EfiACPIReclaimMemory, 0x008 }, 47 { EfiReservedMemoryType, 0x004 }, 48 { EfiRuntimeServicesData, 0x024 }, 49 { EfiRuntimeServicesCode, 0x030 }, 50 { EfiBootServicesCode, 0x180 }, 51 { EfiBootServicesData, 0xF00 }, 52 { EfiMaxMemoryType, 0x000 } 53 }; 54 55 56 EFI_PEI_PPI_DESCRIPTOR mPpiBootMode[] = { 57 { 58 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, 59 &gEfiPeiMasterBootModePpiGuid, 60 NULL 61 } 62 }; 63 64 65 UINT16 mHostBridgeDevId; 66 67 EFI_BOOT_MODE mBootMode = BOOT_WITH_FULL_CONFIGURATION; 68 69 BOOLEAN mS3Supported = FALSE; 70 71 72 VOID 73 AddIoMemoryBaseSizeHob ( 74 EFI_PHYSICAL_ADDRESS MemoryBase, 75 UINT64 MemorySize 76 ) 77 { 78 BuildResourceDescriptorHob ( 79 EFI_RESOURCE_MEMORY_MAPPED_IO, 80 EFI_RESOURCE_ATTRIBUTE_PRESENT | 81 EFI_RESOURCE_ATTRIBUTE_INITIALIZED | 82 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE | 83 EFI_RESOURCE_ATTRIBUTE_TESTED, 84 MemoryBase, 85 MemorySize 86 ); 87 } 88 89 VOID 90 AddReservedMemoryBaseSizeHob ( 91 EFI_PHYSICAL_ADDRESS MemoryBase, 92 UINT64 MemorySize, 93 BOOLEAN Cacheable 94 ) 95 { 96 BuildResourceDescriptorHob ( 97 EFI_RESOURCE_MEMORY_RESERVED, 98 EFI_RESOURCE_ATTRIBUTE_PRESENT | 99 EFI_RESOURCE_ATTRIBUTE_INITIALIZED | 100 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE | 101 (Cacheable ? 102 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE | 103 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE | 104 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE : 105 0 106 ) | 107 EFI_RESOURCE_ATTRIBUTE_TESTED, 108 MemoryBase, 109 MemorySize 110 ); 111 } 112 113 VOID 114 AddIoMemoryRangeHob ( 115 EFI_PHYSICAL_ADDRESS MemoryBase, 116 EFI_PHYSICAL_ADDRESS MemoryLimit 117 ) 118 { 119 AddIoMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase)); 120 } 121 122 123 VOID 124 AddMemoryBaseSizeHob ( 125 EFI_PHYSICAL_ADDRESS MemoryBase, 126 UINT64 MemorySize 127 ) 128 { 129 BuildResourceDescriptorHob ( 130 EFI_RESOURCE_SYSTEM_MEMORY, 131 EFI_RESOURCE_ATTRIBUTE_PRESENT | 132 EFI_RESOURCE_ATTRIBUTE_INITIALIZED | 133 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE | 134 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE | 135 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE | 136 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE | 137 EFI_RESOURCE_ATTRIBUTE_TESTED, 138 MemoryBase, 139 MemorySize 140 ); 141 } 142 143 144 VOID 145 AddMemoryRangeHob ( 146 EFI_PHYSICAL_ADDRESS MemoryBase, 147 EFI_PHYSICAL_ADDRESS MemoryLimit 148 ) 149 { 150 AddMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase)); 151 } 152 153 154 VOID 155 AddUntestedMemoryBaseSizeHob ( 156 EFI_PHYSICAL_ADDRESS MemoryBase, 157 UINT64 MemorySize 158 ) 159 { 160 BuildResourceDescriptorHob ( 161 EFI_RESOURCE_SYSTEM_MEMORY, 162 EFI_RESOURCE_ATTRIBUTE_PRESENT | 163 EFI_RESOURCE_ATTRIBUTE_INITIALIZED | 164 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE | 165 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE | 166 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE | 167 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE, 168 MemoryBase, 169 MemorySize 170 ); 171 } 172 173 174 VOID 175 AddUntestedMemoryRangeHob ( 176 EFI_PHYSICAL_ADDRESS MemoryBase, 177 EFI_PHYSICAL_ADDRESS MemoryLimit 178 ) 179 { 180 AddUntestedMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase)); 181 } 182 183 VOID 184 MemMapInitialization ( 185 VOID 186 ) 187 { 188 // 189 // Create Memory Type Information HOB 190 // 191 BuildGuidDataHob ( 192 &gEfiMemoryTypeInformationGuid, 193 mDefaultMemoryTypeInformation, 194 sizeof(mDefaultMemoryTypeInformation) 195 ); 196 197 // 198 // Add PCI IO Port space available for PCI resource allocations. 199 // 200 BuildResourceDescriptorHob ( 201 EFI_RESOURCE_IO, 202 EFI_RESOURCE_ATTRIBUTE_PRESENT | 203 EFI_RESOURCE_ATTRIBUTE_INITIALIZED, 204 0xC000, 205 0x4000 206 ); 207 208 // 209 // Video memory + Legacy BIOS region 210 // 211 AddIoMemoryRangeHob (0x0A0000, BASE_1MB); 212 213 if (!mXen) { 214 UINT32 TopOfLowRam; 215 UINT32 PciBase; 216 217 TopOfLowRam = GetSystemMemorySizeBelow4gb (); 218 if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) { 219 // 220 // A 3GB base will always fall into Q35's 32-bit PCI host aperture, 221 // regardless of the Q35 MMCONFIG BAR. Correspondingly, QEMU never lets 222 // the RAM below 4 GB exceed it. 223 // 224 PciBase = BASE_2GB + BASE_1GB; 225 ASSERT (TopOfLowRam <= PciBase); 226 } else { 227 PciBase = (TopOfLowRam < BASE_2GB) ? BASE_2GB : TopOfLowRam; 228 } 229 230 // 231 // address purpose size 232 // ------------ -------- ------------------------- 233 // max(top, 2g) PCI MMIO 0xFC000000 - max(top, 2g) 234 // 0xFC000000 gap 44 MB 235 // 0xFEC00000 IO-APIC 4 KB 236 // 0xFEC01000 gap 1020 KB 237 // 0xFED00000 HPET 1 KB 238 // 0xFED00400 gap 111 KB 239 // 0xFED1C000 gap (PIIX4) / RCRB (ICH9) 16 KB 240 // 0xFED20000 gap 896 KB 241 // 0xFEE00000 LAPIC 1 MB 242 // 243 AddIoMemoryRangeHob (PciBase, 0xFC000000); 244 AddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB); 245 AddIoMemoryBaseSizeHob (0xFED00000, SIZE_1KB); 246 if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) { 247 AddIoMemoryBaseSizeHob (ICH9_ROOT_COMPLEX_BASE, SIZE_16KB); 248 } 249 AddIoMemoryBaseSizeHob (PcdGet32(PcdCpuLocalApicBaseAddress), SIZE_1MB); 250 } 251 } 252 253 EFI_STATUS 254 GetNamedFwCfgBoolean ( 255 IN CHAR8 *FwCfgFileName, 256 OUT BOOLEAN *Setting 257 ) 258 { 259 EFI_STATUS Status; 260 FIRMWARE_CONFIG_ITEM FwCfgItem; 261 UINTN FwCfgSize; 262 UINT8 Value[3]; 263 264 Status = QemuFwCfgFindFile (FwCfgFileName, &FwCfgItem, &FwCfgSize); 265 if (EFI_ERROR (Status)) { 266 return Status; 267 } 268 if (FwCfgSize > sizeof Value) { 269 return EFI_BAD_BUFFER_SIZE; 270 } 271 QemuFwCfgSelectItem (FwCfgItem); 272 QemuFwCfgReadBytes (FwCfgSize, Value); 273 274 if ((FwCfgSize == 1) || 275 (FwCfgSize == 2 && Value[1] == '\n') || 276 (FwCfgSize == 3 && Value[1] == '\r' && Value[2] == '\n')) { 277 switch (Value[0]) { 278 case '0': 279 case 'n': 280 case 'N': 281 *Setting = FALSE; 282 return EFI_SUCCESS; 283 284 case '1': 285 case 'y': 286 case 'Y': 287 *Setting = TRUE; 288 return EFI_SUCCESS; 289 290 default: 291 break; 292 } 293 } 294 return EFI_PROTOCOL_ERROR; 295 } 296 297 #define UPDATE_BOOLEAN_PCD_FROM_FW_CFG(TokenName) \ 298 do { \ 299 BOOLEAN Setting; \ 300 \ 301 if (!EFI_ERROR (GetNamedFwCfgBoolean ( \ 302 "opt/ovmf/" #TokenName, &Setting))) { \ 303 PcdSetBool (TokenName, Setting); \ 304 } \ 305 } while (0) 306 307 VOID 308 NoexecDxeInitialization ( 309 VOID 310 ) 311 { 312 UPDATE_BOOLEAN_PCD_FROM_FW_CFG (PcdPropertiesTableEnable); 313 UPDATE_BOOLEAN_PCD_FROM_FW_CFG (PcdSetNxForStack); 314 } 315 316 VOID 317 MiscInitialization ( 318 VOID 319 ) 320 { 321 UINTN PmCmd; 322 UINTN Pmba; 323 UINTN AcpiCtlReg; 324 UINT8 AcpiEnBit; 325 326 // 327 // Disable A20 Mask 328 // 329 IoOr8 (0x92, BIT1); 330 331 // 332 // Build the CPU HOB with guest RAM size dependent address width and 16-bits 333 // of IO space. (Side note: unlike other HOBs, the CPU HOB is needed during 334 // S3 resume as well, so we build it unconditionally.) 335 // 336 BuildCpuHob (mPhysMemAddressWidth, 16); 337 338 // 339 // Determine platform type and save Host Bridge DID to PCD 340 // 341 switch (mHostBridgeDevId) { 342 case INTEL_82441_DEVICE_ID: 343 PmCmd = POWER_MGMT_REGISTER_PIIX4 (PCI_COMMAND_OFFSET); 344 Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA); 345 AcpiCtlReg = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMREGMISC); 346 AcpiEnBit = PIIX4_PMREGMISC_PMIOSE; 347 break; 348 case INTEL_Q35_MCH_DEVICE_ID: 349 PmCmd = POWER_MGMT_REGISTER_Q35 (PCI_COMMAND_OFFSET); 350 Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE); 351 AcpiCtlReg = POWER_MGMT_REGISTER_Q35 (ICH9_ACPI_CNTL); 352 AcpiEnBit = ICH9_ACPI_CNTL_ACPI_EN; 353 break; 354 default: 355 DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n", 356 __FUNCTION__, mHostBridgeDevId)); 357 ASSERT (FALSE); 358 return; 359 } 360 PcdSet16 (PcdOvmfHostBridgePciDevId, mHostBridgeDevId); 361 362 // 363 // If the appropriate IOspace enable bit is set, assume the ACPI PMBA 364 // has been configured (e.g., by Xen) and skip the setup here. 365 // This matches the logic in AcpiTimerLibConstructor (). 366 // 367 if ((PciRead8 (AcpiCtlReg) & AcpiEnBit) == 0) { 368 // 369 // The PEI phase should be exited with fully accessibe ACPI PM IO space: 370 // 1. set PMBA 371 // 372 PciAndThenOr32 (Pmba, (UINT32) ~0xFFC0, PcdGet16 (PcdAcpiPmBaseAddress)); 373 374 // 375 // 2. set PCICMD/IOSE 376 // 377 PciOr8 (PmCmd, EFI_PCI_COMMAND_IO_SPACE); 378 379 // 380 // 3. set ACPI PM IO enable bit (PMREGMISC:PMIOSE or ACPI_CNTL:ACPI_EN) 381 // 382 PciOr8 (AcpiCtlReg, AcpiEnBit); 383 } 384 385 if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) { 386 // 387 // Set Root Complex Register Block BAR 388 // 389 PciWrite32 ( 390 POWER_MGMT_REGISTER_Q35 (ICH9_RCBA), 391 ICH9_ROOT_COMPLEX_BASE | ICH9_RCBA_EN 392 ); 393 } 394 } 395 396 397 VOID 398 BootModeInitialization ( 399 VOID 400 ) 401 { 402 EFI_STATUS Status; 403 404 if (CmosRead8 (0xF) == 0xFE) { 405 mBootMode = BOOT_ON_S3_RESUME; 406 } 407 CmosWrite8 (0xF, 0x00); 408 409 Status = PeiServicesSetBootMode (mBootMode); 410 ASSERT_EFI_ERROR (Status); 411 412 Status = PeiServicesInstallPpi (mPpiBootMode); 413 ASSERT_EFI_ERROR (Status); 414 } 415 416 417 VOID 418 ReserveEmuVariableNvStore ( 419 ) 420 { 421 EFI_PHYSICAL_ADDRESS VariableStore; 422 423 // 424 // Allocate storage for NV variables early on so it will be 425 // at a consistent address. Since VM memory is preserved 426 // across reboots, this allows the NV variable storage to survive 427 // a VM reboot. 428 // 429 VariableStore = 430 (EFI_PHYSICAL_ADDRESS)(UINTN) 431 AllocateAlignedRuntimePages ( 432 EFI_SIZE_TO_PAGES (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize)), 433 PcdGet32 (PcdFlashNvStorageFtwSpareSize) 434 ); 435 DEBUG ((EFI_D_INFO, 436 "Reserved variable store memory: 0x%lX; size: %dkb\n", 437 VariableStore, 438 (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize)) / 1024 439 )); 440 PcdSet64 (PcdEmuVariableNvStoreReserved, VariableStore); 441 } 442 443 444 VOID 445 DebugDumpCmos ( 446 VOID 447 ) 448 { 449 UINT32 Loop; 450 451 DEBUG ((EFI_D_INFO, "CMOS:\n")); 452 453 for (Loop = 0; Loop < 0x80; Loop++) { 454 if ((Loop % 0x10) == 0) { 455 DEBUG ((EFI_D_INFO, "%02x:", Loop)); 456 } 457 DEBUG ((EFI_D_INFO, " %02x", CmosRead8 (Loop))); 458 if ((Loop % 0x10) == 0xf) { 459 DEBUG ((EFI_D_INFO, "\n")); 460 } 461 } 462 } 463 464 465 VOID 466 S3Verification ( 467 VOID 468 ) 469 { 470 #if defined (MDE_CPU_X64) 471 if (FeaturePcdGet (PcdSmmSmramRequire) && mS3Supported) { 472 DEBUG ((EFI_D_ERROR, 473 "%a: S3Resume2Pei doesn't support X64 PEI + SMM yet.\n", __FUNCTION__)); 474 DEBUG ((EFI_D_ERROR, 475 "%a: Please disable S3 on the QEMU command line (see the README),\n", 476 __FUNCTION__)); 477 DEBUG ((EFI_D_ERROR, 478 "%a: or build OVMF with \"OvmfPkgIa32X64.dsc\".\n", __FUNCTION__)); 479 ASSERT (FALSE); 480 CpuDeadLoop (); 481 } 482 #endif 483 } 484 485 486 /** 487 Perform Platform PEI initialization. 488 489 @param FileHandle Handle of the file being invoked. 490 @param PeiServices Describes the list of possible PEI Services. 491 492 @return EFI_SUCCESS The PEIM initialized successfully. 493 494 **/ 495 EFI_STATUS 496 EFIAPI 497 InitializePlatform ( 498 IN EFI_PEI_FILE_HANDLE FileHandle, 499 IN CONST EFI_PEI_SERVICES **PeiServices 500 ) 501 { 502 DEBUG ((EFI_D_ERROR, "Platform PEIM Loaded\n")); 503 504 DebugDumpCmos (); 505 506 XenDetect (); 507 508 if (QemuFwCfgS3Enabled ()) { 509 DEBUG ((EFI_D_INFO, "S3 support was detected on QEMU\n")); 510 mS3Supported = TRUE; 511 } 512 513 S3Verification (); 514 BootModeInitialization (); 515 AddressWidthInitialization (); 516 517 PublishPeiMemory (); 518 519 InitializeRamRegions (); 520 521 if (mXen) { 522 DEBUG ((EFI_D_INFO, "Xen was detected\n")); 523 InitializeXen (); 524 } 525 526 // 527 // Query Host Bridge DID 528 // 529 mHostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID); 530 531 if (mBootMode != BOOT_ON_S3_RESUME) { 532 ReserveEmuVariableNvStore (); 533 PeiFvInitialization (); 534 MemMapInitialization (); 535 NoexecDxeInitialization (); 536 } 537 538 MiscInitialization (); 539 540 return EFI_SUCCESS; 541 } 542