Home | History | Annotate | Download | only in PlatformInitPei
      1 /** @file
      2 
      3   Copyright (c) 2004  - 2014, Intel Corporation. All rights reserved.<BR>
      4 
      5   This program and the accompanying materials are licensed and made available under
      7   the terms and conditions of the BSD License that accompanies this distribution.
      9   The full text of the license may be found at
     11   http://opensource.org/licenses/bsd-license.php.
     13 
     15   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     17   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     19 
     21 
     23 Module Name:
     24 
     25 
     26   Recovery.c
     27 
     28 Abstract:
     29 
     30   Tiano PEIM to provide the platform recovery functionality.
     31 
     32 --*/
     33 
     34 #include "PlatformEarlyInit.h"
     35 
     36 #define PEI_FVMAIN_COMPACT_GUID \
     37   {0x4A538818, 0x5AE0, 0x4eb2, 0xB2, 0xEB, 0x48, 0x8b, 0x23, 0x65, 0x70, 0x22};
     38 
     39 EFI_GUID FvMainCompactFileGuid = PEI_FVMAIN_COMPACT_GUID;
     40 
     41 //
     42 // Required Service
     43 //
     44 EFI_STATUS
     45 EFIAPI
     46 PlatformRecoveryModule (
     47   IN CONST EFI_PEI_SERVICES                       **PeiServices,
     48   IN EFI_PEI_RECOVERY_MODULE_PPI          *This
     49   );
     50 
     51 //
     52 // Module globals
     53 //
     54 
     55 typedef struct {
     56   EFI_GUID  CapsuleGuid;
     57   UINT32    HeaderSize;
     58   UINT32    Flags;
     59   UINT32    CapsuleImageSize;
     60   UINT32    SequenceNumber;
     61   EFI_GUID  InstanceId;
     62   UINT32    OffsetToSplitInformation;
     63   UINT32    OffsetToCapsuleBody;
     64   UINT32    OffsetToOemDefinedHeader;
     65   UINT32    OffsetToAuthorInformation;
     66   UINT32    OffsetToRevisionInformation;
     67   UINT32    OffsetToShortDescription;
     68   UINT32    OffsetToLongDescription;
     69   UINT32    OffsetToApplicableDevices;
     70 } OLD_EFI_CAPSULE_HEADER;
     71 
     72 
     73 static EFI_PEI_RECOVERY_MODULE_PPI mRecoveryPpi = {
     74   PlatformRecoveryModule
     75 };
     76 
     77 static EFI_PEI_PPI_DESCRIPTOR mRecoveryPpiList = {
     78   (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
     79   &gEfiPeiRecoveryModulePpiGuid,
     80   &mRecoveryPpi
     81 };
     82 
     83 /**
     84   Provide the functionality of the Recovery Module.
     85 
     86   @param PeiServices  General purpose services available to every PEIM.
     87 
     88   @retval Status      EFI_SUCCESS if the interface could be successfully
     89                       installed
     90 
     91 **/
     92 EFI_STATUS
     93 EFIAPI
     94 PeimInitializeRecovery (
     95   IN CONST EFI_PEI_SERVICES     **PeiServices
     96   )
     97 {
     98   EFI_STATUS  Status;
     99 
    100   Status = (*PeiServices)->InstallPpi (
    101                              PeiServices,
    102                              &mRecoveryPpiList
    103                              );
    104 
    105   return Status;
    106 }
    107 
    108 /**
    109   Provide the functionality of the Ea Recovery Module.
    110 
    111   @param PeiServices         General purpose services available to every PEIM.
    112   @param This                Pointer to PEI_RECOVERY_MODULE_INTERFACE.
    113 
    114   @retval EFI_SUCCESS        If the interface could be successfully
    115                              installed.
    116   @retval EFI_UNSUPPORTED    Not supported.
    117 
    118 **/
    119 EFI_STATUS
    120 EFIAPI
    121 PlatformRecoveryModule (
    122   IN CONST EFI_PEI_SERVICES               **PeiServices,
    123   IN EFI_PEI_RECOVERY_MODULE_PPI          *This
    124   )
    125 {
    126   EFI_STATUS                            Status;
    127   EFI_PEI_DEVICE_RECOVERY_MODULE_PPI    *DeviceRecoveryModule;
    128   UINTN                                 NumberOfImageProviders;
    129   BOOLEAN                               ProviderAvailable;
    130   UINTN                                 NumberRecoveryCapsules;
    131   UINTN                                 RecoveryCapsuleSize;
    132   EFI_GUID                              DeviceId;
    133   BOOLEAN                               ImageFound;
    134   EFI_PHYSICAL_ADDRESS                  Address;
    135   VOID                                  *Buffer;
    136   OLD_EFI_CAPSULE_HEADER                *CapsuleHeader;
    137   EFI_PEI_HOB_POINTERS                  Hob;
    138   EFI_PEI_HOB_POINTERS                  HobOld;
    139   EFI_HOB_CAPSULE_VOLUME                *CapsuleHob;
    140   BOOLEAN                               HobUpdate;
    141   EFI_FIRMWARE_VOLUME_HEADER            *FvHeader;
    142   UINTN                                 Index;
    143   BOOLEAN                                FoundFvMain;
    144   BOOLEAN                                FoundCapsule;
    145   static EFI_GUID mEfiCapsuleHeaderGuid = EFI_CAPSULE_GUID;
    146   EFI_PEI_STALL_PPI                      *StallPpi;
    147 
    148   (*PeiServices)->ReportStatusCode (
    149                     PeiServices,
    150                     EFI_PROGRESS_CODE,
    151                     EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEIM_PC_RECOVERY_BEGIN,
    152                     0,
    153                     NULL,
    154                     NULL
    155                     );
    156 
    157   Status = (**PeiServices).LocatePpi (
    158               PeiServices,
    159               &gEfiPeiStallPpiGuid,
    160               0,
    161               NULL,
    162               &StallPpi
    163               );
    164   ASSERT_EFI_ERROR (Status);
    165 
    166   StallPpi->Stall(
    167               PeiServices,
    168               StallPpi,
    169               5000000
    170               );
    171 
    172 
    173   Index = 0;
    174 
    175   Status                  = EFI_SUCCESS;
    176   HobUpdate               = FALSE;
    177 
    178   ProviderAvailable       = TRUE;
    179   ImageFound              = FALSE;
    180   NumberOfImageProviders  = 0;
    181 
    182   DeviceRecoveryModule    = NULL;
    183 
    184   FoundCapsule = FALSE;
    185   FoundFvMain = FALSE;
    186 
    187   DEBUG ((EFI_D_ERROR | EFI_D_LOAD, "Recovery Entry\n"));
    188 
    189   //
    190   // Search the platform for some recovery capsule if the DXE IPL
    191   // discovered a recovery condition and has requested a load.
    192   //
    193   while (ProviderAvailable == TRUE) {
    194 
    195     Status = (*PeiServices)->LocatePpi (
    196                                PeiServices,
    197                                &gEfiPeiDeviceRecoveryModulePpiGuid,
    198                                Index,
    199                                NULL,
    200                                &DeviceRecoveryModule
    201                                );
    202 
    203     if (!EFI_ERROR (Status)) {
    204       DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Device Recovery PPI located\n"));
    205       NumberOfImageProviders++;
    206 
    207       Status = DeviceRecoveryModule->GetNumberRecoveryCapsules (
    208                                        (EFI_PEI_SERVICES**)PeiServices,
    209                                        DeviceRecoveryModule,
    210                                        &NumberRecoveryCapsules
    211                                        );
    212 
    213       DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Number Of Recovery Capsules: %d\n", NumberRecoveryCapsules));
    214 
    215       if (NumberRecoveryCapsules == 0) {
    216         Index++;
    217       } else {
    218         break;
    219       }
    220     } else {
    221       ProviderAvailable = FALSE;
    222     }
    223   }
    224 
    225   //
    226   // If there is an image provider, get the capsule ID
    227   //
    228   if (ProviderAvailable) {
    229     RecoveryCapsuleSize = 0;
    230 
    231     Status = DeviceRecoveryModule->GetRecoveryCapsuleInfo (
    232                                     (EFI_PEI_SERVICES**)PeiServices,
    233                                     DeviceRecoveryModule,
    234                                     0,
    235                                     &RecoveryCapsuleSize,
    236                                     &DeviceId
    237                                     );
    238 
    239     if (EFI_ERROR (Status)) {
    240       return Status;
    241     }
    242 
    243     DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Recovery Capsule Size: %d\n", RecoveryCapsuleSize));
    244 
    245     //
    246     // Only support the 2 capsule types known
    247     // Future enhancement is to rank-order the selection
    248     //
    249     if ((!CompareGuid (&DeviceId, &gRecoveryOnFatIdeDiskGuid)) &&
    250         (!CompareGuid (&DeviceId, &gRecoveryOnFatFloppyDiskGuid)) &&
    251         (!CompareGuid (&DeviceId, &gRecoveryOnDataCdGuid)) &&
    252        (!CompareGuid (&DeviceId, &gRecoveryOnFatUsbDiskGuid))
    253         ) {
    254       return EFI_UNSUPPORTED;
    255     }
    256 
    257     Buffer  = NULL;
    258     Status = (*PeiServices)->AllocatePages (
    259                                PeiServices,
    260                                EfiBootServicesCode,
    261                                (RecoveryCapsuleSize - 1) / 0x1000 + 1,
    262                                &Address
    263                                );
    264 
    265     DEBUG ((EFI_D_INFO | EFI_D_LOAD, "AllocatePage Returns: %r\n", Status));
    266 
    267     if (EFI_ERROR(Status)) {
    268       return Status;
    269     }
    270 
    271     Buffer = (UINT8 *) (UINTN) Address;
    272 
    273     (*PeiServices)->ReportStatusCode (
    274                       PeiServices,
    275                       EFI_PROGRESS_CODE,
    276                       EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEIM_PC_CAPSULE_LOAD,
    277                       0,
    278                       NULL,
    279                       NULL
    280                       );
    281 
    282     Status = DeviceRecoveryModule->LoadRecoveryCapsule (
    283                                      (EFI_PEI_SERVICES**)PeiServices,
    284                                      DeviceRecoveryModule,
    285                                      0,
    286                                      Buffer
    287                                      );
    288 
    289     DEBUG ((EFI_D_INFO | EFI_D_LOAD, "LoadRecoveryCapsule Returns: %r\n", Status));
    290 
    291     if (EFI_ERROR (Status)) {
    292       return Status;
    293     }
    294 
    295     //
    296     // Update FV Hob if found
    297     //
    298     Status = (*PeiServices)->GetHobList (PeiServices, &Hob.Raw);
    299     HobOld.Raw  = Hob.Raw;
    300     while (!END_OF_HOB_LIST (Hob)) {
    301       if (Hob.Header->HobType == EFI_HOB_TYPE_FV) {
    302         DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Hob FV Length: %x\n", Hob.FirmwareVolume->Length));
    303         //
    304         // BUGBUG Why is it a FV hob if it is greater than 0x50000?
    305         //
    306         if (Hob.FirmwareVolume->Length > 0x50000) {
    307           HobUpdate = TRUE;
    308           //
    309           // This looks like the Hob we are interested in
    310           //
    311           DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Hob Updated\n"));
    312           Hob.FirmwareVolume->BaseAddress = (UINTN) Buffer;
    313           Hob.FirmwareVolume->Length      = RecoveryCapsuleSize;
    314         }
    315       }
    316       Hob.Raw = GET_NEXT_HOB (Hob);
    317     }
    318 
    319     FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)Buffer;
    320     CapsuleHeader = (OLD_EFI_CAPSULE_HEADER *)Buffer;
    321 
    322     //
    323     // Check if top of file is a capsule
    324     //
    325     if (CompareGuid ((EFI_GUID *)CapsuleHeader, &mEfiCapsuleHeaderGuid)) {
    326       FoundCapsule = TRUE;
    327     } else if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
    328     	//
    329       // Assume the Firmware volume is a "FVMAIN" image
    330       //
    331       FoundFvMain = TRUE;
    332     }
    333 
    334     if (FoundFvMain) {
    335       //
    336       // build FV Hob if it is not built before
    337       //
    338       if (!HobUpdate) {
    339         DEBUG ((EFI_D_INFO | EFI_D_LOAD, "FV Hob is not found, Build FV Hob then..\n"));
    340 
    341        BuildFvHob (
    342          (UINTN)FvHeader,
    343          FvHeader->FvLength
    344           );
    345       }
    346     }
    347 
    348     if (FoundCapsule) {
    349       //
    350       // Build capsule hob
    351       //
    352       Status = (*PeiServices)->CreateHob (
    353                                  PeiServices,
    354                                  EFI_HOB_TYPE_CV,
    355                                  sizeof (EFI_HOB_CAPSULE_VOLUME),
    356                                  &CapsuleHob
    357                                  );
    358       if (EFI_ERROR (Status)) {
    359         return Status;
    360       }
    361       CapsuleHob->BaseAddress = (UINT64)((UINTN)CapsuleHeader + (UINTN)CapsuleHeader->OffsetToCapsuleBody);
    362       CapsuleHob->Length = (UINT64)((UINTN)CapsuleHeader->CapsuleImageSize -(UINTN)CapsuleHeader->OffsetToCapsuleBody);
    363       (*PeiServices)->ReportStatusCode (
    364                         PeiServices,
    365                         EFI_PROGRESS_CODE,
    366                         EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEIM_PC_CAPSULE_START,
    367                         0,
    368                         NULL,
    369                         NULL
    370                         );
    371     }
    372   }
    373   DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Recovery Module Returning: %r\n", Status));
    374   return Status;
    375 }
    376