Home | History | Annotate | Download | only in PlatformPei
      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