Home | History | Annotate | Download | only in PlatformBootManagerLib
      1 /** @file
      2   Platform BDS customizations.
      3 
      4   Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
      5   This program and the accompanying materials
      6   are licensed and made available under the terms and conditions of the BSD License
      7   which accompanies this distribution.  The full text of the license may be found at
      8   http://opensource.org/licenses/bsd-license.php
      9 
     10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "BdsPlatform.h"
     16 #include <Guid/XenInfo.h>
     17 #include <Guid/RootBridgesConnectedEventGroup.h>
     18 #include <Protocol/FirmwareVolume2.h>
     19 
     20 
     21 //
     22 // Global data
     23 //
     24 
     25 VOID          *mEfiDevPathNotifyReg;
     26 EFI_EVENT     mEfiDevPathEvent;
     27 VOID          *mEmuVariableEventReg;
     28 EFI_EVENT     mEmuVariableEvent;
     29 BOOLEAN       mDetectVgaOnly;
     30 UINT16        mHostBridgeDevId;
     31 
     32 //
     33 // Table of host IRQs matching PCI IRQs A-D
     34 // (for configuring PCI Interrupt Line register)
     35 //
     36 CONST UINT8 PciHostIrqs[] = {
     37   0x0a, 0x0a, 0x0b, 0x0b
     38 };
     39 
     40 //
     41 // Type definitions
     42 //
     43 
     44 typedef
     45 EFI_STATUS
     46 (EFIAPI *PROTOCOL_INSTANCE_CALLBACK)(
     47   IN EFI_HANDLE           Handle,
     48   IN VOID                 *Instance,
     49   IN VOID                 *Context
     50   );
     51 
     52 /**
     53   @param[in]  Handle - Handle of PCI device instance
     54   @param[in]  PciIo - PCI IO protocol instance
     55   @param[in]  Pci - PCI Header register block
     56 **/
     57 typedef
     58 EFI_STATUS
     59 (EFIAPI *VISIT_PCI_INSTANCE_CALLBACK)(
     60   IN EFI_HANDLE           Handle,
     61   IN EFI_PCI_IO_PROTOCOL  *PciIo,
     62   IN PCI_TYPE00           *Pci
     63   );
     64 
     65 
     66 //
     67 // Function prototypes
     68 //
     69 
     70 EFI_STATUS
     71 VisitAllInstancesOfProtocol (
     72   IN EFI_GUID                    *Id,
     73   IN PROTOCOL_INSTANCE_CALLBACK  CallBackFunction,
     74   IN VOID                        *Context
     75   );
     76 
     77 EFI_STATUS
     78 VisitAllPciInstancesOfProtocol (
     79   IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
     80   );
     81 
     82 VOID
     83 InstallDevicePathCallback (
     84   VOID
     85   );
     86 
     87 VOID
     88 PlatformRegisterFvBootOption (
     89   EFI_GUID                         *FileGuid,
     90   CHAR16                           *Description,
     91   UINT32                           Attributes
     92   )
     93 {
     94   EFI_STATUS                        Status;
     95   INTN                              OptionIndex;
     96   EFI_BOOT_MANAGER_LOAD_OPTION      NewOption;
     97   EFI_BOOT_MANAGER_LOAD_OPTION      *BootOptions;
     98   UINTN                             BootOptionCount;
     99   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
    100   EFI_LOADED_IMAGE_PROTOCOL         *LoadedImage;
    101   EFI_DEVICE_PATH_PROTOCOL          *DevicePath;
    102 
    103   Status = gBS->HandleProtocol (
    104                   gImageHandle,
    105                   &gEfiLoadedImageProtocolGuid,
    106                   (VOID **) &LoadedImage
    107                   );
    108   ASSERT_EFI_ERROR (Status);
    109 
    110   EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
    111   DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);
    112   ASSERT (DevicePath != NULL);
    113   DevicePath = AppendDevicePathNode (
    114                  DevicePath,
    115                  (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
    116                  );
    117   ASSERT (DevicePath != NULL);
    118 
    119   Status = EfiBootManagerInitializeLoadOption (
    120              &NewOption,
    121              LoadOptionNumberUnassigned,
    122              LoadOptionTypeBoot,
    123              Attributes,
    124              Description,
    125              DevicePath,
    126              NULL,
    127              0
    128              );
    129   ASSERT_EFI_ERROR (Status);
    130   FreePool (DevicePath);
    131 
    132   BootOptions = EfiBootManagerGetLoadOptions (
    133                   &BootOptionCount, LoadOptionTypeBoot
    134                   );
    135 
    136   OptionIndex = EfiBootManagerFindLoadOption (
    137                   &NewOption, BootOptions, BootOptionCount
    138                   );
    139 
    140   if (OptionIndex == -1) {
    141     Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);
    142     ASSERT_EFI_ERROR (Status);
    143   }
    144   EfiBootManagerFreeLoadOption (&NewOption);
    145   EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
    146 }
    147 
    148 /**
    149   Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options
    150   whose device paths do not resolve exactly to an FvFile in the system.
    151 
    152   This removes any boot options that point to binaries built into the firmware
    153   and have become stale due to any of the following:
    154   - DXEFV's base address or size changed (historical),
    155   - DXEFV's FvNameGuid changed,
    156   - the FILE_GUID of the pointed-to binary changed,
    157   - the referenced binary is no longer built into the firmware.
    158 
    159   EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only
    160   avoids exact duplicates.
    161 **/
    162 VOID
    163 RemoveStaleFvFileOptions (
    164   VOID
    165   )
    166 {
    167   EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
    168   UINTN                        BootOptionCount;
    169   UINTN                        Index;
    170 
    171   BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount,
    172                   LoadOptionTypeBoot);
    173 
    174   for (Index = 0; Index < BootOptionCount; ++Index) {
    175     EFI_DEVICE_PATH_PROTOCOL *Node1, *Node2, *SearchNode;
    176     EFI_STATUS               Status;
    177     EFI_HANDLE               FvHandle;
    178 
    179     //
    180     // If the device path starts with neither MemoryMapped(...) nor Fv(...),
    181     // then keep the boot option.
    182     //
    183     Node1 = BootOptions[Index].FilePath;
    184     if (!(DevicePathType (Node1) == HARDWARE_DEVICE_PATH &&
    185           DevicePathSubType (Node1) == HW_MEMMAP_DP) &&
    186         !(DevicePathType (Node1) == MEDIA_DEVICE_PATH &&
    187           DevicePathSubType (Node1) == MEDIA_PIWG_FW_VOL_DP)) {
    188       continue;
    189     }
    190 
    191     //
    192     // If the second device path node is not FvFile(...), then keep the boot
    193     // option.
    194     //
    195     Node2 = NextDevicePathNode (Node1);
    196     if (DevicePathType (Node2) != MEDIA_DEVICE_PATH ||
    197         DevicePathSubType (Node2) != MEDIA_PIWG_FW_FILE_DP) {
    198       continue;
    199     }
    200 
    201     //
    202     // Locate the Firmware Volume2 protocol instance that is denoted by the
    203     // boot option. If this lookup fails (i.e., the boot option references a
    204     // firmware volume that doesn't exist), then we'll proceed to delete the
    205     // boot option.
    206     //
    207     SearchNode = Node1;
    208     Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid,
    209                     &SearchNode, &FvHandle);
    210 
    211     if (!EFI_ERROR (Status)) {
    212       //
    213       // The firmware volume was found; now let's see if it contains the FvFile
    214       // identified by GUID.
    215       //
    216       EFI_FIRMWARE_VOLUME2_PROTOCOL     *FvProtocol;
    217       MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFileNode;
    218       UINTN                             BufferSize;
    219       EFI_FV_FILETYPE                   FoundType;
    220       EFI_FV_FILE_ATTRIBUTES            FileAttributes;
    221       UINT32                            AuthenticationStatus;
    222 
    223       Status = gBS->HandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid,
    224                       (VOID **)&FvProtocol);
    225       ASSERT_EFI_ERROR (Status);
    226 
    227       FvFileNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)Node2;
    228       //
    229       // Buffer==NULL means we request metadata only: BufferSize, FoundType,
    230       // FileAttributes.
    231       //
    232       Status = FvProtocol->ReadFile (
    233                              FvProtocol,
    234                              &FvFileNode->FvFileName, // NameGuid
    235                              NULL,                    // Buffer
    236                              &BufferSize,
    237                              &FoundType,
    238                              &FileAttributes,
    239                              &AuthenticationStatus
    240                              );
    241       if (!EFI_ERROR (Status)) {
    242         //
    243         // The FvFile was found. Keep the boot option.
    244         //
    245         continue;
    246       }
    247     }
    248 
    249     //
    250     // Delete the boot option.
    251     //
    252     Status = EfiBootManagerDeleteLoadOptionVariable (
    253                BootOptions[Index].OptionNumber, LoadOptionTypeBoot);
    254     DEBUG_CODE (
    255       CHAR16 *DevicePathString;
    256 
    257       DevicePathString = ConvertDevicePathToText(BootOptions[Index].FilePath,
    258                            FALSE, FALSE);
    259       DEBUG ((
    260         EFI_ERROR (Status) ? EFI_D_WARN : EFI_D_VERBOSE,
    261         "%a: removing stale Boot#%04x %s: %r\n",
    262         __FUNCTION__,
    263         (UINT32)BootOptions[Index].OptionNumber,
    264         DevicePathString == NULL ? L"<unavailable>" : DevicePathString,
    265         Status
    266         ));
    267       if (DevicePathString != NULL) {
    268         FreePool (DevicePathString);
    269       }
    270       );
    271   }
    272 
    273   EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
    274 }
    275 
    276 VOID
    277 PlatformRegisterOptionsAndKeys (
    278   VOID
    279   )
    280 {
    281   EFI_STATUS                   Status;
    282   EFI_INPUT_KEY                Enter;
    283   EFI_INPUT_KEY                F2;
    284   EFI_INPUT_KEY                Esc;
    285   EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
    286 
    287   //
    288   // Register ENTER as CONTINUE key
    289   //
    290   Enter.ScanCode    = SCAN_NULL;
    291   Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
    292   Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
    293   ASSERT_EFI_ERROR (Status);
    294 
    295   //
    296   // Map F2 to Boot Manager Menu
    297   //
    298   F2.ScanCode     = SCAN_F2;
    299   F2.UnicodeChar  = CHAR_NULL;
    300   Esc.ScanCode    = SCAN_ESC;
    301   Esc.UnicodeChar = CHAR_NULL;
    302   Status = EfiBootManagerGetBootManagerMenu (&BootOption);
    303   ASSERT_EFI_ERROR (Status);
    304   Status = EfiBootManagerAddKeyOptionVariable (
    305              NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL
    306              );
    307   ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
    308   Status = EfiBootManagerAddKeyOptionVariable (
    309              NULL, (UINT16) BootOption.OptionNumber, 0, &Esc, NULL
    310              );
    311   ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
    312 }
    313 
    314 EFI_STATUS
    315 EFIAPI
    316 ConnectRootBridge (
    317   IN EFI_HANDLE  RootBridgeHandle,
    318   IN VOID        *Instance,
    319   IN VOID        *Context
    320   );
    321 
    322 STATIC
    323 VOID
    324 SaveS3BootScript (
    325   VOID
    326   );
    327 
    328 //
    329 // BDS Platform Functions
    330 //
    331 VOID
    332 EFIAPI
    333 PlatformBootManagerBeforeConsole (
    334   VOID
    335   )
    336 /*++
    337 
    338 Routine Description:
    339 
    340   Platform Bds init. Include the platform firmware vendor, revision
    341   and so crc check.
    342 
    343 Arguments:
    344 
    345 Returns:
    346 
    347   None.
    348 
    349 --*/
    350 {
    351   EFI_HANDLE    Handle;
    352   EFI_STATUS    Status;
    353   RETURN_STATUS PcdStatus;
    354 
    355   DEBUG ((EFI_D_INFO, "PlatformBootManagerBeforeConsole\n"));
    356   InstallDevicePathCallback ();
    357 
    358   VisitAllInstancesOfProtocol (&gEfiPciRootBridgeIoProtocolGuid,
    359     ConnectRootBridge, NULL);
    360 
    361   //
    362   // Signal the ACPI platform driver that it can download QEMU ACPI tables.
    363   //
    364   EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid);
    365 
    366   //
    367   // We can't signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers
    368   // the preparation of S3 system information. That logic has a hard dependency
    369   // on the presence of the FACS ACPI table. Since our ACPI tables are only
    370   // installed after PCI enumeration completes, we must not trigger the S3 save
    371   // earlier, hence we can't signal End-of-Dxe earlier.
    372   //
    373   EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
    374 
    375   if (QemuFwCfgS3Enabled ()) {
    376     //
    377     // Save the boot script too. Note that this will require us to emit the
    378     // DxeSmmReadyToLock event just below, which in turn locks down SMM.
    379     //
    380     SaveS3BootScript ();
    381   }
    382 
    383   //
    384   // Prevent further changes to LockBoxes or SMRAM.
    385   //
    386   Handle = NULL;
    387   Status = gBS->InstallProtocolInterface (&Handle,
    388                   &gEfiDxeSmmReadyToLockProtocolGuid, EFI_NATIVE_INTERFACE,
    389                   NULL);
    390   ASSERT_EFI_ERROR (Status);
    391 
    392   //
    393   // Dispatch deferred images after EndOfDxe event and ReadyToLock installation.
    394   //
    395   EfiBootManagerDispatchDeferredImages ();
    396 
    397   PlatformInitializeConsole (gPlatformConsole);
    398   PcdStatus = PcdSet16S (PcdPlatformBootTimeOut,
    399                 GetFrontPageTimeoutFromQemu ());
    400   ASSERT_RETURN_ERROR (PcdStatus);
    401 
    402   PlatformRegisterOptionsAndKeys ();
    403 }
    404 
    405 
    406 EFI_STATUS
    407 EFIAPI
    408 ConnectRootBridge (
    409   IN EFI_HANDLE  RootBridgeHandle,
    410   IN VOID        *Instance,
    411   IN VOID        *Context
    412   )
    413 {
    414   EFI_STATUS Status;
    415 
    416   //
    417   // Make the PCI bus driver connect the root bridge, non-recursively. This
    418   // will produce a number of child handles with PciIo on them.
    419   //
    420   Status = gBS->ConnectController (
    421                   RootBridgeHandle, // ControllerHandle
    422                   NULL,             // DriverImageHandle
    423                   NULL,             // RemainingDevicePath -- produce all
    424                                     //   children
    425                   FALSE             // Recursive
    426                   );
    427   return Status;
    428 }
    429 
    430 
    431 EFI_STATUS
    432 PrepareLpcBridgeDevicePath (
    433   IN EFI_HANDLE                DeviceHandle
    434   )
    435 /*++
    436 
    437 Routine Description:
    438 
    439   Add IsaKeyboard to ConIn,
    440   add IsaSerial to ConOut, ConIn, ErrOut.
    441   LPC Bridge: 06 01 00
    442 
    443 Arguments:
    444 
    445   DeviceHandle            - Handle of PCIIO protocol.
    446 
    447 Returns:
    448 
    449   EFI_SUCCESS             - LPC bridge is added to ConOut, ConIn, and ErrOut.
    450   EFI_STATUS              - No LPC bridge is added.
    451 
    452 --*/
    453 {
    454   EFI_STATUS                Status;
    455   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
    456   EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;
    457   CHAR16                    *DevPathStr;
    458 
    459   DevicePath = NULL;
    460   Status = gBS->HandleProtocol (
    461                   DeviceHandle,
    462                   &gEfiDevicePathProtocolGuid,
    463                   (VOID*)&DevicePath
    464                   );
    465   if (EFI_ERROR (Status)) {
    466     return Status;
    467   }
    468   TempDevicePath = DevicePath;
    469 
    470   //
    471   // Register Keyboard
    472   //
    473   DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode);
    474 
    475   EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
    476 
    477   //
    478   // Register COM1
    479   //
    480   DevicePath = TempDevicePath;
    481   gPnp16550ComPortDeviceNode.UID = 0;
    482 
    483   DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);
    484   DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
    485   DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
    486 
    487   //
    488   // Print Device Path
    489   //
    490   DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
    491   if (DevPathStr != NULL) {
    492     DEBUG((
    493       EFI_D_INFO,
    494       "BdsPlatform.c+%d: COM%d DevPath: %s\n",
    495       __LINE__,
    496       gPnp16550ComPortDeviceNode.UID + 1,
    497       DevPathStr
    498       ));
    499     FreePool(DevPathStr);
    500   }
    501 
    502   EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
    503   EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
    504   EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
    505 
    506   //
    507   // Register COM2
    508   //
    509   DevicePath = TempDevicePath;
    510   gPnp16550ComPortDeviceNode.UID = 1;
    511 
    512   DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);
    513   DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
    514   DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
    515 
    516   //
    517   // Print Device Path
    518   //
    519   DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
    520   if (DevPathStr != NULL) {
    521     DEBUG((
    522       EFI_D_INFO,
    523       "BdsPlatform.c+%d: COM%d DevPath: %s\n",
    524       __LINE__,
    525       gPnp16550ComPortDeviceNode.UID + 1,
    526       DevPathStr
    527       ));
    528     FreePool(DevPathStr);
    529   }
    530 
    531   EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
    532   EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
    533   EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
    534 
    535   return EFI_SUCCESS;
    536 }
    537 
    538 EFI_STATUS
    539 GetGopDevicePath (
    540    IN  EFI_DEVICE_PATH_PROTOCOL *PciDevicePath,
    541    OUT EFI_DEVICE_PATH_PROTOCOL **GopDevicePath
    542    )
    543 {
    544   UINTN                           Index;
    545   EFI_STATUS                      Status;
    546   EFI_HANDLE                      PciDeviceHandle;
    547   EFI_DEVICE_PATH_PROTOCOL        *TempDevicePath;
    548   EFI_DEVICE_PATH_PROTOCOL        *TempPciDevicePath;
    549   UINTN                           GopHandleCount;
    550   EFI_HANDLE                      *GopHandleBuffer;
    551 
    552   if (PciDevicePath == NULL || GopDevicePath == NULL) {
    553     return EFI_INVALID_PARAMETER;
    554   }
    555 
    556   //
    557   // Initialize the GopDevicePath to be PciDevicePath
    558   //
    559   *GopDevicePath    = PciDevicePath;
    560   TempPciDevicePath = PciDevicePath;
    561 
    562   Status = gBS->LocateDevicePath (
    563                   &gEfiDevicePathProtocolGuid,
    564                   &TempPciDevicePath,
    565                   &PciDeviceHandle
    566                   );
    567   if (EFI_ERROR (Status)) {
    568     return Status;
    569   }
    570 
    571   //
    572   // Try to connect this handle, so that GOP driver could start on this
    573   // device and create child handles with GraphicsOutput Protocol installed
    574   // on them, then we get device paths of these child handles and select
    575   // them as possible console device.
    576   //
    577   gBS->ConnectController (PciDeviceHandle, NULL, NULL, FALSE);
    578 
    579   Status = gBS->LocateHandleBuffer (
    580                   ByProtocol,
    581                   &gEfiGraphicsOutputProtocolGuid,
    582                   NULL,
    583                   &GopHandleCount,
    584                   &GopHandleBuffer
    585                   );
    586   if (!EFI_ERROR (Status)) {
    587     //
    588     // Add all the child handles as possible Console Device
    589     //
    590     for (Index = 0; Index < GopHandleCount; Index++) {
    591       Status = gBS->HandleProtocol (GopHandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID*)&TempDevicePath);
    592       if (EFI_ERROR (Status)) {
    593         continue;
    594       }
    595       if (CompareMem (
    596             PciDevicePath,
    597             TempDevicePath,
    598             GetDevicePathSize (PciDevicePath) - END_DEVICE_PATH_LENGTH
    599             ) == 0) {
    600         //
    601         // In current implementation, we only enable one of the child handles
    602         // as console device, i.e. sotre one of the child handle's device
    603         // path to variable "ConOut"
    604         // In future, we could select all child handles to be console device
    605         //
    606 
    607         *GopDevicePath = TempDevicePath;
    608 
    609         //
    610         // Delete the PCI device's path that added by GetPlugInPciVgaDevicePath()
    611         // Add the integrity GOP device path.
    612         //
    613         EfiBootManagerUpdateConsoleVariable (ConOutDev, NULL, PciDevicePath);
    614         EfiBootManagerUpdateConsoleVariable (ConOutDev, TempDevicePath, NULL);
    615       }
    616     }
    617     gBS->FreePool (GopHandleBuffer);
    618   }
    619 
    620   return EFI_SUCCESS;
    621 }
    622 
    623 EFI_STATUS
    624 PreparePciDisplayDevicePath (
    625   IN EFI_HANDLE                DeviceHandle
    626   )
    627 /*++
    628 
    629 Routine Description:
    630 
    631   Add PCI VGA to ConOut.
    632   PCI VGA: 03 00 00
    633 
    634 Arguments:
    635 
    636   DeviceHandle            - Handle of PCIIO protocol.
    637 
    638 Returns:
    639 
    640   EFI_SUCCESS             - PCI VGA is added to ConOut.
    641   EFI_STATUS              - No PCI VGA device is added.
    642 
    643 --*/
    644 {
    645   EFI_STATUS                Status;
    646   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
    647   EFI_DEVICE_PATH_PROTOCOL  *GopDevicePath;
    648 
    649   DevicePath    = NULL;
    650   GopDevicePath = NULL;
    651   Status = gBS->HandleProtocol (
    652                   DeviceHandle,
    653                   &gEfiDevicePathProtocolGuid,
    654                   (VOID*)&DevicePath
    655                   );
    656   if (EFI_ERROR (Status)) {
    657     return Status;
    658   }
    659 
    660   GetGopDevicePath (DevicePath, &GopDevicePath);
    661   DevicePath = GopDevicePath;
    662 
    663   EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
    664 
    665   return EFI_SUCCESS;
    666 }
    667 
    668 EFI_STATUS
    669 PreparePciSerialDevicePath (
    670   IN EFI_HANDLE                DeviceHandle
    671   )
    672 /*++
    673 
    674 Routine Description:
    675 
    676   Add PCI Serial to ConOut, ConIn, ErrOut.
    677   PCI Serial: 07 00 02
    678 
    679 Arguments:
    680 
    681   DeviceHandle            - Handle of PCIIO protocol.
    682 
    683 Returns:
    684 
    685   EFI_SUCCESS             - PCI Serial is added to ConOut, ConIn, and ErrOut.
    686   EFI_STATUS              - No PCI Serial device is added.
    687 
    688 --*/
    689 {
    690   EFI_STATUS                Status;
    691   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
    692 
    693   DevicePath = NULL;
    694   Status = gBS->HandleProtocol (
    695                   DeviceHandle,
    696                   &gEfiDevicePathProtocolGuid,
    697                   (VOID*)&DevicePath
    698                   );
    699   if (EFI_ERROR (Status)) {
    700     return Status;
    701   }
    702 
    703   DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
    704   DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
    705 
    706   EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
    707   EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
    708   EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
    709 
    710   return EFI_SUCCESS;
    711 }
    712 
    713 EFI_STATUS
    714 VisitAllInstancesOfProtocol (
    715   IN EFI_GUID                    *Id,
    716   IN PROTOCOL_INSTANCE_CALLBACK  CallBackFunction,
    717   IN VOID                        *Context
    718   )
    719 {
    720   EFI_STATUS                Status;
    721   UINTN                     HandleCount;
    722   EFI_HANDLE                *HandleBuffer;
    723   UINTN                     Index;
    724   VOID                      *Instance;
    725 
    726   //
    727   // Start to check all the PciIo to find all possible device
    728   //
    729   HandleCount = 0;
    730   HandleBuffer = NULL;
    731   Status = gBS->LocateHandleBuffer (
    732                   ByProtocol,
    733                   Id,
    734                   NULL,
    735                   &HandleCount,
    736                   &HandleBuffer
    737                   );
    738   if (EFI_ERROR (Status)) {
    739     return Status;
    740   }
    741 
    742   for (Index = 0; Index < HandleCount; Index++) {
    743     Status = gBS->HandleProtocol (HandleBuffer[Index], Id, &Instance);
    744     if (EFI_ERROR (Status)) {
    745       continue;
    746     }
    747 
    748     Status = (*CallBackFunction) (
    749                HandleBuffer[Index],
    750                Instance,
    751                Context
    752                );
    753   }
    754 
    755   gBS->FreePool (HandleBuffer);
    756 
    757   return EFI_SUCCESS;
    758 }
    759 
    760 
    761 EFI_STATUS
    762 EFIAPI
    763 VisitingAPciInstance (
    764   IN EFI_HANDLE  Handle,
    765   IN VOID        *Instance,
    766   IN VOID        *Context
    767   )
    768 {
    769   EFI_STATUS                Status;
    770   EFI_PCI_IO_PROTOCOL       *PciIo;
    771   PCI_TYPE00                Pci;
    772 
    773   PciIo = (EFI_PCI_IO_PROTOCOL*) Instance;
    774 
    775   //
    776   // Check for all PCI device
    777   //
    778   Status = PciIo->Pci.Read (
    779                     PciIo,
    780                     EfiPciIoWidthUint32,
    781                     0,
    782                     sizeof (Pci) / sizeof (UINT32),
    783                     &Pci
    784                     );
    785   if (EFI_ERROR (Status)) {
    786     return Status;
    787   }
    788 
    789   return (*(VISIT_PCI_INSTANCE_CALLBACK)(UINTN) Context) (
    790            Handle,
    791            PciIo,
    792            &Pci
    793            );
    794 
    795 }
    796 
    797 
    798 
    799 EFI_STATUS
    800 VisitAllPciInstances (
    801   IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
    802   )
    803 {
    804   return VisitAllInstancesOfProtocol (
    805            &gEfiPciIoProtocolGuid,
    806            VisitingAPciInstance,
    807            (VOID*)(UINTN) CallBackFunction
    808            );
    809 }
    810 
    811 
    812 /**
    813   Do platform specific PCI Device check and add them to
    814   ConOut, ConIn, ErrOut.
    815 
    816   @param[in]  Handle - Handle of PCI device instance
    817   @param[in]  PciIo - PCI IO protocol instance
    818   @param[in]  Pci - PCI Header register block
    819 
    820   @retval EFI_SUCCESS - PCI Device check and Console variable update successfully.
    821   @retval EFI_STATUS - PCI Device check or Console variable update fail.
    822 
    823 **/
    824 EFI_STATUS
    825 EFIAPI
    826 DetectAndPreparePlatformPciDevicePath (
    827   IN EFI_HANDLE           Handle,
    828   IN EFI_PCI_IO_PROTOCOL  *PciIo,
    829   IN PCI_TYPE00           *Pci
    830   )
    831 {
    832   EFI_STATUS                Status;
    833 
    834   Status = PciIo->Attributes (
    835     PciIo,
    836     EfiPciIoAttributeOperationEnable,
    837     EFI_PCI_DEVICE_ENABLE,
    838     NULL
    839     );
    840   ASSERT_EFI_ERROR (Status);
    841 
    842   if (!mDetectVgaOnly) {
    843     //
    844     // Here we decide whether it is LPC Bridge
    845     //
    846     if ((IS_PCI_LPC (Pci)) ||
    847         ((IS_PCI_ISA_PDECODE (Pci)) &&
    848          (Pci->Hdr.VendorId == 0x8086) &&
    849          (Pci->Hdr.DeviceId == 0x7000)
    850         )
    851        ) {
    852       //
    853       // Add IsaKeyboard to ConIn,
    854       // add IsaSerial to ConOut, ConIn, ErrOut
    855       //
    856       DEBUG ((EFI_D_INFO, "Found LPC Bridge device\n"));
    857       PrepareLpcBridgeDevicePath (Handle);
    858       return EFI_SUCCESS;
    859     }
    860     //
    861     // Here we decide which Serial device to enable in PCI bus
    862     //
    863     if (IS_PCI_16550SERIAL (Pci)) {
    864       //
    865       // Add them to ConOut, ConIn, ErrOut.
    866       //
    867       DEBUG ((EFI_D_INFO, "Found PCI 16550 SERIAL device\n"));
    868       PreparePciSerialDevicePath (Handle);
    869       return EFI_SUCCESS;
    870     }
    871   }
    872 
    873   //
    874   // Here we decide which display device to enable in PCI bus
    875   //
    876   if (IS_PCI_DISPLAY (Pci)) {
    877     //
    878     // Add them to ConOut.
    879     //
    880     DEBUG ((EFI_D_INFO, "Found PCI display device\n"));
    881     PreparePciDisplayDevicePath (Handle);
    882     return EFI_SUCCESS;
    883   }
    884 
    885   return Status;
    886 }
    887 
    888 
    889 /**
    890   Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
    891 
    892   @param[in]  DetectVgaOnly - Only detect VGA device if it's TRUE.
    893 
    894   @retval EFI_SUCCESS - PCI Device check and Console variable update successfully.
    895   @retval EFI_STATUS - PCI Device check or Console variable update fail.
    896 
    897 **/
    898 EFI_STATUS
    899 DetectAndPreparePlatformPciDevicePaths (
    900   BOOLEAN DetectVgaOnly
    901   )
    902 {
    903   mDetectVgaOnly = DetectVgaOnly;
    904   return VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath);
    905 }
    906 
    907 
    908 VOID
    909 PlatformInitializeConsole (
    910   IN PLATFORM_CONSOLE_CONNECT_ENTRY   *PlatformConsole
    911   )
    912 /*++
    913 
    914 Routine Description:
    915 
    916   Connect the predefined platform default console device. Always try to find
    917   and enable the vga device if have.
    918 
    919 Arguments:
    920 
    921   PlatformConsole         - Predefined platform default console device array.
    922 --*/
    923 {
    924   UINTN                              Index;
    925   EFI_DEVICE_PATH_PROTOCOL           *VarConout;
    926   EFI_DEVICE_PATH_PROTOCOL           *VarConin;
    927 
    928   //
    929   // Connect RootBridge
    930   //
    931   GetEfiGlobalVariable2 (EFI_CON_OUT_VARIABLE_NAME, (VOID **) &VarConout, NULL);
    932   GetEfiGlobalVariable2 (EFI_CON_IN_VARIABLE_NAME, (VOID **) &VarConin, NULL);
    933 
    934   if (VarConout == NULL || VarConin == NULL) {
    935     //
    936     // Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
    937     //
    938     DetectAndPreparePlatformPciDevicePaths (FALSE);
    939 
    940     //
    941     // Have chance to connect the platform default console,
    942     // the platform default console is the minimum device group
    943     // the platform should support
    944     //
    945     for (Index = 0; PlatformConsole[Index].DevicePath != NULL; ++Index) {
    946       //
    947       // Update the console variable with the connect type
    948       //
    949       if ((PlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) {
    950         EfiBootManagerUpdateConsoleVariable (ConIn, PlatformConsole[Index].DevicePath, NULL);
    951       }
    952       if ((PlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) {
    953         EfiBootManagerUpdateConsoleVariable (ConOut, PlatformConsole[Index].DevicePath, NULL);
    954       }
    955       if ((PlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) {
    956         EfiBootManagerUpdateConsoleVariable (ErrOut, PlatformConsole[Index].DevicePath, NULL);
    957       }
    958     }
    959   } else {
    960     //
    961     // Only detect VGA device and add them to ConOut
    962     //
    963     DetectAndPreparePlatformPciDevicePaths (TRUE);
    964   }
    965 }
    966 
    967 
    968 /**
    969   Configure PCI Interrupt Line register for applicable devices
    970   Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
    971 
    972   @param[in]  Handle - Handle of PCI device instance
    973   @param[in]  PciIo - PCI IO protocol instance
    974   @param[in]  PciHdr - PCI Header register block
    975 
    976   @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
    977 
    978 **/
    979 EFI_STATUS
    980 EFIAPI
    981 SetPciIntLine (
    982   IN EFI_HANDLE           Handle,
    983   IN EFI_PCI_IO_PROTOCOL  *PciIo,
    984   IN PCI_TYPE00           *PciHdr
    985   )
    986 {
    987   EFI_DEVICE_PATH_PROTOCOL  *DevPathNode;
    988   EFI_DEVICE_PATH_PROTOCOL  *DevPath;
    989   UINTN                     RootSlot;
    990   UINTN                     Idx;
    991   UINT8                     IrqLine;
    992   EFI_STATUS                Status;
    993   UINT32                    RootBusNumber;
    994 
    995   Status = EFI_SUCCESS;
    996 
    997   if (PciHdr->Device.InterruptPin != 0) {
    998 
    999     DevPathNode = DevicePathFromHandle (Handle);
   1000     ASSERT (DevPathNode != NULL);
   1001     DevPath = DevPathNode;
   1002 
   1003     RootBusNumber = 0;
   1004     if (DevicePathType (DevPathNode) == ACPI_DEVICE_PATH &&
   1005         DevicePathSubType (DevPathNode) == ACPI_DP &&
   1006         ((ACPI_HID_DEVICE_PATH *)DevPathNode)->HID == EISA_PNP_ID(0x0A03)) {
   1007       RootBusNumber = ((ACPI_HID_DEVICE_PATH *)DevPathNode)->UID;
   1008     }
   1009 
   1010     //
   1011     // Compute index into PciHostIrqs[] table by walking
   1012     // the device path and adding up all device numbers
   1013     //
   1014     Status = EFI_NOT_FOUND;
   1015     RootSlot = 0;
   1016     Idx = PciHdr->Device.InterruptPin - 1;
   1017     while (!IsDevicePathEnd (DevPathNode)) {
   1018       if (DevicePathType (DevPathNode) == HARDWARE_DEVICE_PATH &&
   1019           DevicePathSubType (DevPathNode) == HW_PCI_DP) {
   1020 
   1021         Idx += ((PCI_DEVICE_PATH *)DevPathNode)->Device;
   1022 
   1023         //
   1024         // Unlike SeaBIOS, which starts climbing from the leaf device
   1025         // up toward the root, we traverse the device path starting at
   1026         // the root moving toward the leaf node.
   1027         // The slot number of the top-level parent bridge is needed for
   1028         // Q35 cases with more than 24 slots on the root bus.
   1029         //
   1030         if (Status != EFI_SUCCESS) {
   1031           Status = EFI_SUCCESS;
   1032           RootSlot = ((PCI_DEVICE_PATH *)DevPathNode)->Device;
   1033         }
   1034       }
   1035 
   1036       DevPathNode = NextDevicePathNode (DevPathNode);
   1037     }
   1038     if (EFI_ERROR (Status)) {
   1039       return Status;
   1040     }
   1041     if (RootBusNumber == 0 && RootSlot == 0) {
   1042       DEBUG((
   1043         EFI_D_ERROR,
   1044         "%a: PCI host bridge (00:00.0) should have no interrupts!\n",
   1045         __FUNCTION__
   1046         ));
   1047       ASSERT (FALSE);
   1048     }
   1049 
   1050     //
   1051     // Final PciHostIrqs[] index calculation depends on the platform
   1052     // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
   1053     //
   1054     switch (mHostBridgeDevId) {
   1055       case INTEL_82441_DEVICE_ID:
   1056         Idx -= 1;
   1057         break;
   1058       case INTEL_Q35_MCH_DEVICE_ID:
   1059         //
   1060         // SeaBIOS contains the following comment:
   1061         // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
   1062         //  with a different starting index - see q35-acpi-dsdt.dsl.
   1063         //
   1064         //  Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
   1065         //
   1066         if (RootSlot > 24) {
   1067           //
   1068           // in this case, subtract back out RootSlot from Idx
   1069           // (SeaBIOS never adds it to begin with, but that would make our
   1070           //  device path traversal loop above too awkward)
   1071           //
   1072           Idx -= RootSlot;
   1073         }
   1074         break;
   1075       default:
   1076         ASSERT (FALSE); // should never get here
   1077     }
   1078     Idx %= ARRAY_SIZE (PciHostIrqs);
   1079     IrqLine = PciHostIrqs[Idx];
   1080 
   1081     DEBUG_CODE_BEGIN ();
   1082     {
   1083       CHAR16        *DevPathString;
   1084       STATIC CHAR16 Fallback[] = L"<failed to convert>";
   1085       UINTN         Segment, Bus, Device, Function;
   1086 
   1087       DevPathString = ConvertDevicePathToText (DevPath, FALSE, FALSE);
   1088       if (DevPathString == NULL) {
   1089         DevPathString = Fallback;
   1090       }
   1091       Status = PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function);
   1092       ASSERT_EFI_ERROR (Status);
   1093 
   1094       DEBUG ((EFI_D_VERBOSE, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__,
   1095         (UINT32)Bus, (UINT32)Device, (UINT32)Function, DevPathString,
   1096         IrqLine));
   1097 
   1098       if (DevPathString != Fallback) {
   1099         FreePool (DevPathString);
   1100       }
   1101     }
   1102     DEBUG_CODE_END ();
   1103 
   1104     //
   1105     // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
   1106     //
   1107     Status = PciIo->Pci.Write (
   1108                PciIo,
   1109                EfiPciIoWidthUint8,
   1110                PCI_INT_LINE_OFFSET,
   1111                1,
   1112                &IrqLine
   1113                );
   1114   }
   1115 
   1116   return Status;
   1117 }
   1118 
   1119 
   1120 VOID
   1121 PciAcpiInitialization (
   1122   )
   1123 {
   1124   UINTN  Pmba;
   1125 
   1126   //
   1127   // Query Host Bridge DID to determine platform type
   1128   //
   1129   mHostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);
   1130   switch (mHostBridgeDevId) {
   1131     case INTEL_82441_DEVICE_ID:
   1132       Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);
   1133       //
   1134       // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
   1135       //
   1136       PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A
   1137       PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B
   1138       PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C
   1139       PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D
   1140       break;
   1141     case INTEL_Q35_MCH_DEVICE_ID:
   1142       Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);
   1143       //
   1144       // 00:1f.0 LPC Bridge (Q35) LNK routing targets
   1145       //
   1146       PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A
   1147       PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B
   1148       PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C
   1149       PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D
   1150       PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E
   1151       PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F
   1152       PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G
   1153       PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H
   1154       break;
   1155     default:
   1156       DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
   1157         __FUNCTION__, mHostBridgeDevId));
   1158       ASSERT (FALSE);
   1159       return;
   1160   }
   1161 
   1162   //
   1163   // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
   1164   //
   1165   VisitAllPciInstances (SetPciIntLine);
   1166 
   1167   //
   1168   // Set ACPI SCI_EN bit in PMCNTRL
   1169   //
   1170   IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);
   1171 }
   1172 
   1173 /**
   1174   This function detects if OVMF is running on Xen.
   1175 
   1176 **/
   1177 STATIC
   1178 BOOLEAN
   1179 XenDetected (
   1180   VOID
   1181   )
   1182 {
   1183   EFI_HOB_GUID_TYPE         *GuidHob;
   1184   STATIC INTN               FoundHob = -1;
   1185 
   1186   if (FoundHob == 0) {
   1187     return FALSE;
   1188   } else if (FoundHob == 1) {
   1189     return TRUE;
   1190   }
   1191 
   1192   //
   1193   // See if a XenInfo HOB is available
   1194   //
   1195   GuidHob = GetFirstGuidHob (&gEfiXenInfoGuid);
   1196   if (GuidHob == NULL) {
   1197     FoundHob = 0;
   1198     return FALSE;
   1199   }
   1200 
   1201   FoundHob = 1;
   1202   return TRUE;
   1203 }
   1204 
   1205 EFI_STATUS
   1206 EFIAPI
   1207 ConnectRecursivelyIfPciMassStorage (
   1208   IN EFI_HANDLE           Handle,
   1209   IN EFI_PCI_IO_PROTOCOL  *Instance,
   1210   IN PCI_TYPE00           *PciHeader
   1211   )
   1212 {
   1213   EFI_STATUS                Status;
   1214   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
   1215   CHAR16                    *DevPathStr;
   1216 
   1217   //
   1218   // Recognize PCI Mass Storage, and Xen PCI devices
   1219   //
   1220   if (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE) ||
   1221       (XenDetected() && IS_CLASS2 (PciHeader, 0xFF, 0x80))) {
   1222     DevicePath = NULL;
   1223     Status = gBS->HandleProtocol (
   1224                     Handle,
   1225                     &gEfiDevicePathProtocolGuid,
   1226                     (VOID*)&DevicePath
   1227                     );
   1228     if (EFI_ERROR (Status)) {
   1229       return Status;
   1230     }
   1231 
   1232     //
   1233     // Print Device Path
   1234     //
   1235     DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
   1236     if (DevPathStr != NULL) {
   1237       DEBUG((
   1238         EFI_D_INFO,
   1239         "Found %s device: %s\n",
   1240         IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE) ? L"Mass Storage" : L"Xen",
   1241         DevPathStr
   1242         ));
   1243       FreePool(DevPathStr);
   1244     }
   1245 
   1246     Status = gBS->ConnectController (Handle, NULL, NULL, TRUE);
   1247     if (EFI_ERROR (Status)) {
   1248       return Status;
   1249     }
   1250 
   1251   }
   1252 
   1253   return EFI_SUCCESS;
   1254 }
   1255 
   1256 
   1257 /**
   1258   This notification function is invoked when the
   1259   EMU Variable FVB has been changed.
   1260 
   1261   @param  Event                 The event that occurred
   1262   @param  Context               For EFI compatibility.  Not used.
   1263 
   1264 **/
   1265 VOID
   1266 EFIAPI
   1267 EmuVariablesUpdatedCallback (
   1268   IN  EFI_EVENT Event,
   1269   IN  VOID      *Context
   1270   )
   1271 {
   1272   DEBUG ((EFI_D_INFO, "EmuVariablesUpdatedCallback\n"));
   1273   UpdateNvVarsOnFileSystem ();
   1274 }
   1275 
   1276 
   1277 EFI_STATUS
   1278 EFIAPI
   1279 VisitingFileSystemInstance (
   1280   IN EFI_HANDLE  Handle,
   1281   IN VOID        *Instance,
   1282   IN VOID        *Context
   1283   )
   1284 {
   1285   EFI_STATUS      Status;
   1286   STATIC BOOLEAN  ConnectedToFileSystem = FALSE;
   1287   RETURN_STATUS   PcdStatus;
   1288 
   1289   if (ConnectedToFileSystem) {
   1290     return EFI_ALREADY_STARTED;
   1291   }
   1292 
   1293   Status = ConnectNvVarsToFileSystem (Handle);
   1294   if (EFI_ERROR (Status)) {
   1295     return Status;
   1296   }
   1297 
   1298   ConnectedToFileSystem = TRUE;
   1299   mEmuVariableEvent =
   1300     EfiCreateProtocolNotifyEvent (
   1301       &gEfiDevicePathProtocolGuid,
   1302       TPL_CALLBACK,
   1303       EmuVariablesUpdatedCallback,
   1304       NULL,
   1305       &mEmuVariableEventReg
   1306       );
   1307   PcdStatus = PcdSet64S (PcdEmuVariableEvent,
   1308                 (UINT64)(UINTN) mEmuVariableEvent);
   1309   ASSERT_RETURN_ERROR (PcdStatus);
   1310 
   1311   return EFI_SUCCESS;
   1312 }
   1313 
   1314 
   1315 VOID
   1316 PlatformBdsRestoreNvVarsFromHardDisk (
   1317   )
   1318 {
   1319   VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage);
   1320   VisitAllInstancesOfProtocol (
   1321     &gEfiSimpleFileSystemProtocolGuid,
   1322     VisitingFileSystemInstance,
   1323     NULL
   1324     );
   1325 
   1326 }
   1327 
   1328 VOID
   1329 PlatformBdsConnectSequence (
   1330   VOID
   1331   )
   1332 /*++
   1333 
   1334 Routine Description:
   1335 
   1336   Connect with predefined platform connect sequence,
   1337   the OEM/IBV can customize with their own connect sequence.
   1338 
   1339 Arguments:
   1340 
   1341   None.
   1342 
   1343 Returns:
   1344 
   1345   None.
   1346 
   1347 --*/
   1348 {
   1349   UINTN Index;
   1350 
   1351   DEBUG ((EFI_D_INFO, "PlatformBdsConnectSequence\n"));
   1352 
   1353   Index = 0;
   1354 
   1355   //
   1356   // Here we can get the customized platform connect sequence
   1357   // Notes: we can connect with new variable which record the
   1358   // last time boots connect device path sequence
   1359   //
   1360   while (gPlatformConnectSequence[Index] != NULL) {
   1361     //
   1362     // Build the platform boot option
   1363     //
   1364     EfiBootManagerConnectDevicePath (gPlatformConnectSequence[Index], NULL);
   1365     Index++;
   1366   }
   1367 
   1368   //
   1369   // Just use the simple policy to connect all devices
   1370   //
   1371   DEBUG ((EFI_D_INFO, "EfiBootManagerConnectAll\n"));
   1372   EfiBootManagerConnectAll ();
   1373 
   1374   PciAcpiInitialization ();
   1375 }
   1376 
   1377 /**
   1378   Save the S3 boot script.
   1379 
   1380   Note that DxeSmmReadyToLock must be signaled after this function returns;
   1381   otherwise the script wouldn't be saved actually.
   1382 **/
   1383 STATIC
   1384 VOID
   1385 SaveS3BootScript (
   1386   VOID
   1387   )
   1388 {
   1389   EFI_STATUS                 Status;
   1390   EFI_S3_SAVE_STATE_PROTOCOL *BootScript;
   1391   STATIC CONST UINT8         Info[] = { 0xDE, 0xAD, 0xBE, 0xEF };
   1392 
   1393   Status = gBS->LocateProtocol (&gEfiS3SaveStateProtocolGuid, NULL,
   1394                   (VOID **) &BootScript);
   1395   ASSERT_EFI_ERROR (Status);
   1396 
   1397   //
   1398   // Despite the opcode documentation in the PI spec, the protocol
   1399   // implementation embeds a deep copy of the info in the boot script, rather
   1400   // than storing just a pointer to runtime or NVS storage.
   1401   //
   1402   Status = BootScript->Write(BootScript, EFI_BOOT_SCRIPT_INFORMATION_OPCODE,
   1403                          (UINT32) sizeof Info,
   1404                          (EFI_PHYSICAL_ADDRESS)(UINTN) &Info);
   1405   ASSERT_EFI_ERROR (Status);
   1406 }
   1407 
   1408 
   1409 VOID
   1410 EFIAPI
   1411 PlatformBootManagerAfterConsole (
   1412   VOID
   1413   )
   1414 /*++
   1415 
   1416 Routine Description:
   1417 
   1418   The function will execute with as the platform policy, current policy
   1419   is driven by boot mode. IBV/OEM can customize this code for their specific
   1420   policy action.
   1421 
   1422 --*/
   1423 {
   1424   EFI_BOOT_MODE                      BootMode;
   1425 
   1426   DEBUG ((EFI_D_INFO, "PlatformBootManagerAfterConsole\n"));
   1427 
   1428   if (PcdGetBool (PcdOvmfFlashVariablesEnable)) {
   1429     DEBUG ((EFI_D_INFO, "PlatformBdsPolicyBehavior: not restoring NvVars "
   1430       "from disk since flash variables appear to be supported.\n"));
   1431   } else {
   1432     //
   1433     // Try to restore variables from the hard disk early so
   1434     // they can be used for the other BDS connect operations.
   1435     //
   1436     PlatformBdsRestoreNvVarsFromHardDisk ();
   1437   }
   1438 
   1439   //
   1440   // Get current Boot Mode
   1441   //
   1442   BootMode = GetBootModeHob ();
   1443   DEBUG ((EFI_D_ERROR, "Boot Mode:%x\n", BootMode));
   1444 
   1445   //
   1446   // Go the different platform policy with different boot mode
   1447   // Notes: this part code can be change with the table policy
   1448   //
   1449   ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION);
   1450 
   1451   //
   1452   // Logo show
   1453   //
   1454   BootLogoEnableLogo ();
   1455 
   1456   //
   1457   // Perform some platform specific connect sequence
   1458   //
   1459   PlatformBdsConnectSequence ();
   1460 
   1461   //
   1462   // Process QEMU's -kernel command line option
   1463   //
   1464   TryRunningQemuKernel ();
   1465 
   1466   EfiBootManagerRefreshAllBootOption ();
   1467 
   1468   //
   1469   // Register UEFI Shell
   1470   //
   1471   PlatformRegisterFvBootOption (
   1472     PcdGetPtr (PcdShellFile), L"EFI Internal Shell", LOAD_OPTION_ACTIVE
   1473     );
   1474 
   1475   RemoveStaleFvFileOptions ();
   1476   SetBootOrderFromQemu ();
   1477 }
   1478 
   1479 /**
   1480   This notification function is invoked when an instance of the
   1481   EFI_DEVICE_PATH_PROTOCOL is produced.
   1482 
   1483   @param  Event                 The event that occurred
   1484   @param  Context               For EFI compatibility.  Not used.
   1485 
   1486 **/
   1487 VOID
   1488 EFIAPI
   1489 NotifyDevPath (
   1490   IN  EFI_EVENT Event,
   1491   IN  VOID      *Context
   1492   )
   1493 {
   1494   EFI_HANDLE                            Handle;
   1495   EFI_STATUS                            Status;
   1496   UINTN                                 BufferSize;
   1497   EFI_DEVICE_PATH_PROTOCOL             *DevPathNode;
   1498   ATAPI_DEVICE_PATH                    *Atapi;
   1499 
   1500   //
   1501   // Examine all new handles
   1502   //
   1503   for (;;) {
   1504     //
   1505     // Get the next handle
   1506     //
   1507     BufferSize = sizeof (Handle);
   1508     Status = gBS->LocateHandle (
   1509               ByRegisterNotify,
   1510               NULL,
   1511               mEfiDevPathNotifyReg,
   1512               &BufferSize,
   1513               &Handle
   1514               );
   1515 
   1516     //
   1517     // If not found, we're done
   1518     //
   1519     if (EFI_NOT_FOUND == Status) {
   1520       break;
   1521     }
   1522 
   1523     if (EFI_ERROR (Status)) {
   1524       continue;
   1525     }
   1526 
   1527     //
   1528     // Get the DevicePath protocol on that handle
   1529     //
   1530     Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&DevPathNode);
   1531     ASSERT_EFI_ERROR (Status);
   1532 
   1533     while (!IsDevicePathEnd (DevPathNode)) {
   1534       //
   1535       // Find the handler to dump this device path node
   1536       //
   1537       if (
   1538            (DevicePathType(DevPathNode) == MESSAGING_DEVICE_PATH) &&
   1539            (DevicePathSubType(DevPathNode) == MSG_ATAPI_DP)
   1540          ) {
   1541         Atapi = (ATAPI_DEVICE_PATH*) DevPathNode;
   1542         PciOr16 (
   1543           PCI_LIB_ADDRESS (
   1544             0,
   1545             1,
   1546             1,
   1547             (Atapi->PrimarySecondary == 1) ? 0x42: 0x40
   1548             ),
   1549           BIT15
   1550           );
   1551       }
   1552 
   1553       //
   1554       // Next device path node
   1555       //
   1556       DevPathNode = NextDevicePathNode (DevPathNode);
   1557     }
   1558   }
   1559 
   1560   return;
   1561 }
   1562 
   1563 
   1564 VOID
   1565 InstallDevicePathCallback (
   1566   VOID
   1567   )
   1568 {
   1569   DEBUG ((EFI_D_INFO, "Registered NotifyDevPath Event\n"));
   1570   mEfiDevPathEvent = EfiCreateProtocolNotifyEvent (
   1571                           &gEfiDevicePathProtocolGuid,
   1572                           TPL_CALLBACK,
   1573                           NotifyDevPath,
   1574                           NULL,
   1575                           &mEfiDevPathNotifyReg
   1576                           );
   1577 }
   1578 
   1579 /**
   1580   This function is called each second during the boot manager waits the timeout.
   1581 
   1582   @param TimeoutRemain  The remaining timeout.
   1583 **/
   1584 VOID
   1585 EFIAPI
   1586 PlatformBootManagerWaitCallback (
   1587   UINT16          TimeoutRemain
   1588   )
   1589 {
   1590   EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;
   1591   EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;
   1592   UINT16                              Timeout;
   1593 
   1594   Timeout = PcdGet16 (PcdPlatformBootTimeOut);
   1595 
   1596   Black.Raw = 0x00000000;
   1597   White.Raw = 0x00FFFFFF;
   1598 
   1599   BootLogoUpdateProgress (
   1600     White.Pixel,
   1601     Black.Pixel,
   1602     L"Start boot option",
   1603     White.Pixel,
   1604     (Timeout - TimeoutRemain) * 100 / Timeout,
   1605     0
   1606     );
   1607 }
   1608 
   1609