Recovery.c revision 3cbfba02fef9dae07a041fdbf2e89611d72d6f90
1/** @file
2
3  Copyright (c) 2004  - 2014, Intel Corporation. All rights reserved.<BR>
4
5
6  This program and the accompanying materials are licensed and made available under
7
8  the terms and conditions of the BSD License that accompanies this distribution.
9
10  The full text of the license may be found at
11
12  http://opensource.org/licenses/bsd-license.php.
13
14
15
16  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
17
18  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19
20
21
22
23Module Name:
24
25
26  Recovery.c
27
28Abstract:
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
39EFI_GUID FvMainCompactFileGuid = PEI_FVMAIN_COMPACT_GUID;
40
41//
42// Required Service
43//
44EFI_STATUS
45EFIAPI
46PlatformRecoveryModule (
47  IN CONST EFI_PEI_SERVICES                       **PeiServices,
48  IN EFI_PEI_RECOVERY_MODULE_PPI          *This
49  );
50
51//
52// Module globals
53//
54
55typedef 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
73static EFI_PEI_RECOVERY_MODULE_PPI mRecoveryPpi = {
74  PlatformRecoveryModule
75};
76
77static 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**/
92EFI_STATUS
93EFIAPI
94PeimInitializeRecovery (
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**/
119EFI_STATUS
120EFIAPI
121PlatformRecoveryModule (
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