Home | History | Annotate | Download | only in Generic
      1 /** @file
      2 Install Platform EFI_PEI_RECOVERY_MODULE_PPI and Implementation of
      3 EFI_PEI_LOAD_RECOVERY_CAPSULE service.
      4 
      5 Copyright (c) 2013 Intel Corporation.
      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 #include "CommonHeader.h"
     18 #include "PlatformEarlyInit.h"
     19 
     20 #include <Ppi/BlockIo.h>
     21 
     22 //
     23 // Capsule Types supported in this platform module
     24 //
     25 #include <Guid/CapsuleOnFatFloppyDisk.h>
     26 #include <Guid/CapsuleOnFatIdeDisk.h>
     27 #include <Guid/CapsuleOnFatUsbDisk.h>
     28 #include <Guid/CapsuleOnDataCD.h>
     29 #include <Guid/QuarkCapsuleGuid.h>
     30 
     31 #include <Ppi/RecoveryModule.h>
     32 #include <Ppi/DeviceRecoveryModule.h>
     33 
     34 #include <Library/PeiServicesLib.h>
     35 
     36 //
     37 // Required Service
     38 //
     39 EFI_STATUS
     40 EFIAPI
     41 PlatformRecoveryModule (
     42   IN EFI_PEI_SERVICES                       **PeiServices,
     43   IN EFI_PEI_RECOVERY_MODULE_PPI          *This
     44   );
     45 
     46 VOID
     47 AssertNoCapsulesError (
     48   IN EFI_PEI_SERVICES **PeiServices
     49   );
     50 
     51 VOID
     52 AssertMediaDeviceError (
     53   IN EFI_PEI_SERVICES **PeiServices
     54   );
     55 
     56 VOID
     57 ReportLoadCapsuleSuccess (
     58   IN EFI_PEI_SERVICES **PeiServices
     59   );
     60 
     61 VOID
     62 CheckIfMediaPresentOnBlockIoDevice (
     63   IN EFI_PEI_SERVICES   **PeiServices,
     64   IN OUT BOOLEAN        *MediaDeviceError,
     65   IN OUT BOOLEAN        *MediaPresent
     66   );
     67 
     68 //
     69 // Module globals
     70 //
     71 EFI_PEI_RECOVERY_MODULE_PPI  mRecoveryPpi = { PlatformRecoveryModule };
     72 
     73 EFI_PEI_PPI_DESCRIPTOR         mRecoveryPpiList = {
     74   (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
     75   &gEfiPeiRecoveryModulePpiGuid,
     76   &mRecoveryPpi
     77 };
     78 
     79 EFI_STATUS
     80 EFIAPI
     81 PeimInitializeRecovery (
     82   IN EFI_PEI_SERVICES     **PeiServices
     83   )
     84 /*++
     85 
     86 Routine Description:
     87 
     88   Provide the functionality of the Recovery Module.
     89 
     90 Arguments:
     91 
     92   PeiServices  -  General purpose services available to every PEIM.
     93 
     94 Returns:
     95 
     96   EFI_SUCCESS  -  If the interface could be successfully
     97                   installed.
     98 
     99 --*/
    100 {
    101   EFI_STATUS  Status;
    102 
    103   Status = PeiServicesInstallPpi (&mRecoveryPpiList);
    104 
    105   return Status;
    106 }
    107 
    108 EFI_STATUS
    109 EFIAPI
    110 PlatformRecoveryModule (
    111   IN EFI_PEI_SERVICES                       **PeiServices,
    112   IN EFI_PEI_RECOVERY_MODULE_PPI            *This
    113   )
    114 /*++
    115 
    116 Routine Description:
    117 
    118   Provide the functionality of the Platform Recovery Module.
    119 
    120 Arguments:
    121 
    122   PeiServices  -  General purpose services available to every PEIM.
    123   This         -  Pointer to EFI_PEI_RECOVERY_MODULE_PPI.
    124 
    125 Returns:
    126 
    127   EFI_SUCCESS      -  If the interface could be successfully
    128                       installed.
    129   EFI_UNSUPPORTED  -  Not supported.
    130 
    131 --*/
    132 {
    133   EFI_STATUS                            Status;
    134   EFI_PEI_DEVICE_RECOVERY_MODULE_PPI    *DeviceRecoveryModule;
    135   UINTN                                 NumberOfImageProviders;
    136   BOOLEAN                               ProviderAvailable;
    137   UINTN                                 NumberRecoveryCapsules;
    138   UINTN                                 RecoveryCapsuleSize;
    139   EFI_GUID                              DeviceId;
    140   BOOLEAN                               ImageFound;
    141   EFI_PHYSICAL_ADDRESS                  Address;
    142   VOID                                  *Buffer;
    143   EFI_CAPSULE_HEADER                    *CapsuleHeader;
    144   EFI_PEI_HOB_POINTERS                  Hob;
    145   EFI_PEI_HOB_POINTERS                  HobOld;
    146   BOOLEAN                               HobUpdate;
    147   EFI_FIRMWARE_VOLUME_HEADER            *FvHeader;
    148   UINTN                                 Index;
    149   EFI_STATUS                            AuthStatus;
    150   EFI_GUID                              mEfiCapsuleHeaderGuid = QUARK_CAPSULE_GUID;
    151 
    152   Index = 0;
    153 
    154   Status                  = EFI_SUCCESS;
    155   AuthStatus              = EFI_SUCCESS;
    156   HobUpdate               = FALSE;
    157 
    158   ProviderAvailable       = TRUE;
    159   ImageFound              = FALSE;
    160   NumberOfImageProviders  = 0;
    161 
    162   DeviceRecoveryModule    = NULL;
    163 
    164   DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Recovery Entry\n"));
    165 
    166   //
    167   // Search the platform for some recovery capsule if the DXE IPL
    168   // discovered a recovery condition and has requested a load.
    169   //
    170   while (ProviderAvailable) {
    171 
    172     Status = PeiServicesLocatePpi (
    173               &gEfiPeiDeviceRecoveryModulePpiGuid,
    174               Index,
    175               NULL,
    176               (VOID **)&DeviceRecoveryModule
    177               );
    178 
    179     if (!EFI_ERROR (Status)) {
    180       DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Device Recovery PPI located\n"));
    181       NumberOfImageProviders++;
    182 
    183       Status = DeviceRecoveryModule->GetNumberRecoveryCapsules (
    184                                       PeiServices,
    185                                       DeviceRecoveryModule,
    186                                       &NumberRecoveryCapsules
    187                                       );
    188 
    189       DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Number Of Recovery Capsules: %d\n", NumberRecoveryCapsules));
    190 
    191       if (NumberRecoveryCapsules == 0) {
    192         Index++;
    193       } else {
    194         break;
    195       }
    196     } else {
    197       ProviderAvailable = FALSE;
    198     }
    199   }
    200   //
    201   // The number of recovery capsules is 0.
    202   //
    203   if (!ProviderAvailable) {
    204     AssertNoCapsulesError (PeiServices);
    205   }
    206   //
    207   // If there is an image provider, get the capsule ID
    208   //
    209   if (ProviderAvailable) {
    210     RecoveryCapsuleSize = 0;
    211     if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
    212       Status = DeviceRecoveryModule->GetRecoveryCapsuleInfo (
    213                                       PeiServices,
    214                                       DeviceRecoveryModule,
    215                                       0,
    216                                       &RecoveryCapsuleSize,
    217                                       &DeviceId
    218                                       );
    219     } else {
    220       Status = DeviceRecoveryModule->GetRecoveryCapsuleInfo (
    221                   PeiServices,
    222                   DeviceRecoveryModule,
    223                   1,
    224                   &RecoveryCapsuleSize,
    225                   &DeviceId
    226                   );
    227 
    228 
    229   }
    230 
    231     if (EFI_ERROR (Status)) {
    232       return Status;
    233     }
    234 
    235     DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Recovery Capsule Size: %d\n", RecoveryCapsuleSize));
    236 
    237     //
    238     // Only support the 2 capsule types known
    239     // Future enhancement is to rank-order the selection
    240     //
    241     if ((!CompareGuid (&DeviceId, &gPeiCapsuleOnFatIdeDiskGuid)) &&
    242         (!CompareGuid (&DeviceId, &gPeiCapsuleOnDataCDGuid)) &&
    243        (!CompareGuid (&DeviceId, &gPeiCapsuleOnFatUsbDiskGuid))
    244         ) {
    245       return EFI_UNSUPPORTED;
    246     }
    247 
    248     Buffer  = NULL;
    249     Address = (UINTN) AllocatePages ((RecoveryCapsuleSize - 1) / 0x1000 + 1);
    250     ASSERT (Address);
    251 
    252     Buffer = (UINT8 *) (UINTN) Address;
    253     if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
    254       Status = DeviceRecoveryModule->LoadRecoveryCapsule (
    255                                       PeiServices,
    256                                       DeviceRecoveryModule,
    257                                       0,
    258                                       Buffer
    259                                       );
    260      } else {
    261        Status = DeviceRecoveryModule->LoadRecoveryCapsule (
    262                                         PeiServices,
    263                                         DeviceRecoveryModule,
    264                                         1,
    265                                         Buffer
    266                                         );
    267 
    268      }
    269 
    270     DEBUG ((EFI_D_INFO | EFI_D_LOAD, "LoadRecoveryCapsule Returns: %r\n", Status));
    271 
    272     if (Status == EFI_DEVICE_ERROR) {
    273       AssertMediaDeviceError (PeiServices);
    274     }
    275 
    276     if (EFI_ERROR (Status)) {
    277       return Status;
    278     } else {
    279       ReportLoadCapsuleSuccess (PeiServices);
    280     }
    281 
    282     //
    283     // Update FV Hob if found
    284     //
    285     Buffer  = (VOID *)((UINT8 *) Buffer);
    286     Status      = PeiServicesGetHobList ((VOID **)&Hob.Raw);
    287     HobOld.Raw  = Hob.Raw;
    288     while (!END_OF_HOB_LIST (Hob)) {
    289       if (Hob.Header->HobType == EFI_HOB_TYPE_FV) {
    290         DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Hob FV Length: %x\n", Hob.FirmwareVolume->Length));
    291 
    292         if (Hob.FirmwareVolume->BaseAddress == (UINTN) PcdGet32 (PcdFlashFvMainBase)) {
    293           HobUpdate = TRUE;
    294           //
    295           // This looks like the Hob we are interested in
    296           //
    297           DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Hob Updated\n"));
    298           Hob.FirmwareVolume->BaseAddress = (UINTN) Buffer;
    299           Hob.FirmwareVolume->Length      = RecoveryCapsuleSize;
    300         }
    301       }
    302 
    303       Hob.Raw = GET_NEXT_HOB (Hob);
    304     }
    305     //
    306     // Check if the top of the file is a firmware volume header
    307     //
    308     FvHeader      = (EFI_FIRMWARE_VOLUME_HEADER *) Buffer;
    309     CapsuleHeader = (EFI_CAPSULE_HEADER *) Buffer;
    310     if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
    311       //
    312       // build FV Hob if it is not built before
    313       //
    314       if (!HobUpdate) {
    315         DEBUG ((EFI_D_INFO | EFI_D_LOAD, "FV Hob is not found, Build FV Hob then..\n"));
    316         BuildFvHob (
    317           (UINTN) Buffer,
    318           FvHeader->FvLength
    319           );
    320 
    321         DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Install FV Info PPI..\n"));
    322 
    323         PeiServicesInstallFvInfoPpi (
    324           NULL,
    325           Buffer,
    326           (UINT32) FvHeader->FvLength,
    327           NULL,
    328           NULL
    329         );
    330       }
    331       //
    332       // Point to the location immediately after the FV.
    333       //
    334       CapsuleHeader = (EFI_CAPSULE_HEADER *) ((UINT8 *) Buffer + FvHeader->FvLength);
    335     }
    336 
    337     //
    338     // Check if pointer is still within the buffer
    339     //
    340     if ((UINTN) CapsuleHeader < (UINTN) ((UINT8 *) Buffer + RecoveryCapsuleSize)) {
    341 
    342       //
    343       // Check if it is a capsule
    344       //
    345       if (CompareGuid ((EFI_GUID *) CapsuleHeader, &mEfiCapsuleHeaderGuid)) {
    346 
    347         //
    348         // Set bootmode to capsule update so the capsule hob gets the right bootmode in the hob header.
    349         //
    350         Status = PeiServicesSetBootMode (BOOT_ON_FLASH_UPDATE);
    351         if (EFI_ERROR (Status)) {
    352           return Status;
    353         }
    354 
    355         //
    356         // Build capsule hob
    357         //
    358         BuildCvHob ((EFI_PHYSICAL_ADDRESS)(UINTN)CapsuleHeader, (UINT64)CapsuleHeader->CapsuleImageSize);
    359       }
    360     }
    361   }
    362 
    363   DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Recovery Module Returning: %r\n", Status));
    364   return Status;
    365 }
    366 
    367 /*
    368   AssertNoCapsulesError:
    369   There were no recovery capsules found.
    370   Case 1: Report the error that no recovery block io device/media is readable and assert.
    371   Case 2: Report the error that there is no media present on any recovery block io device and assert.
    372   Case 3: There is media present on some recovery block io device,
    373           but there is no recovery capsule on it.  Report the error and assert.
    374 */
    375 VOID
    376 AssertNoCapsulesError (
    377   IN EFI_PEI_SERVICES **PeiServices
    378   )
    379 {
    380   BOOLEAN MediaDeviceError;
    381   BOOLEAN MediaPresent;
    382 
    383   MediaDeviceError  = TRUE;
    384   MediaPresent      = FALSE;
    385 
    386   CheckIfMediaPresentOnBlockIoDevice (PeiServices, &MediaDeviceError, &MediaPresent);
    387 /*  if (MediaDeviceError) {
    388     ReportStatusCode (
    389       (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),
    390       (EFI_PERIPHERAL_RECOVERY_MEDIA | EFI_P_EC_MEDIA_DEVICE_ERROR)
    391       );
    392 
    393   } else if (!MediaPresent) {
    394     ReportStatusCode (
    395       (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),
    396       (EFI_PERIPHERAL_RECOVERY_MEDIA | EFI_P_EC_MEDIA_NOT_PRESENT)
    397       );
    398 
    399   } else {
    400     ReportStatusCode (
    401       (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),
    402       (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEIM_EC_NO_RECOVERY_CAPSULE)
    403       );
    404   }*/
    405   //
    406   // Hang.
    407   //
    408   CpuDeadLoop();
    409 }
    410 
    411 #define MAX_BLOCK_IO_PPI  32
    412 
    413 /*
    414   CheckIfMediaPresentOnBlockIoDevice:
    415   Checks to see whether there was a media device error or to see if there is media present.
    416 */
    417 VOID
    418 CheckIfMediaPresentOnBlockIoDevice (
    419   IN EFI_PEI_SERVICES   **PeiServices,
    420   IN OUT BOOLEAN        *MediaDeviceError,
    421   IN OUT BOOLEAN        *MediaPresent
    422   )
    423 {
    424   EFI_STATUS                      Status;
    425   UINTN                           BlockIoPpiInstance;
    426   EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi;
    427   UINTN                           NumberBlockDevices;
    428   EFI_PEI_BLOCK_IO_MEDIA          Media;
    429 
    430   *MediaDeviceError = TRUE;
    431   *MediaPresent     = FALSE;
    432 
    433   for (BlockIoPpiInstance = 0; BlockIoPpiInstance < MAX_BLOCK_IO_PPI; BlockIoPpiInstance++) {
    434     Status = PeiServicesLocatePpi (
    435               &gEfiPeiVirtualBlockIoPpiGuid,
    436               BlockIoPpiInstance,
    437               NULL,
    438               (VOID **)&BlockIoPpi
    439               );
    440     if (EFI_ERROR (Status)) {
    441       //
    442       // Done with all Block Io Ppis
    443       //
    444       break;
    445     }
    446 
    447     Status = BlockIoPpi->GetNumberOfBlockDevices (
    448                           PeiServices,
    449                           BlockIoPpi,
    450                           &NumberBlockDevices
    451                           );
    452     if (EFI_ERROR (Status) || (NumberBlockDevices == 0)) {
    453       continue;
    454     }
    455     //
    456     // Just retrieve the first block
    457     //
    458     Status = BlockIoPpi->GetBlockDeviceMediaInfo (
    459                           PeiServices,
    460                           BlockIoPpi,
    461                           0,
    462                           &Media
    463                           );
    464     if (!EFI_ERROR (Status)) {
    465       *MediaDeviceError = FALSE;
    466       if (Media.MediaPresent) {
    467         *MediaPresent = TRUE;
    468         break;
    469       }
    470     }
    471   }
    472 }
    473 
    474 VOID
    475 AssertMediaDeviceError (
    476   IN EFI_PEI_SERVICES **PeiServices
    477   )
    478 {
    479 /*  ReportStatusCode (
    480     (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),
    481     (EFI_PERIPHERAL_RECOVERY_MEDIA | EFI_P_EC_MEDIA_DEVICE_ERROR)
    482     );
    483 */
    484   CpuDeadLoop ();
    485 }
    486 
    487 VOID
    488 ReportLoadCapsuleSuccess (
    489   IN EFI_PEI_SERVICES **PeiServices
    490   )
    491 {
    492   //
    493   // EFI_SW_PEI_PC_CAPSULE_START: (from the status code spec):
    494   // Loaded the recovery capsule.  About to hand off control to the capsule.
    495   //
    496 /*  ReportStatusCode (
    497     EFI_PROGRESS_CODE,
    498     (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEIM_PC_CAPSULE_LOAD_SUCCESS)
    499     );*/
    500 }
    501 
    502