• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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.
PeimInitializeRecovery(IN CONST EFI_PEI_SERVICES ** PeiServices)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.
PlatformRecoveryModule(IN CONST EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_RECOVERY_MODULE_PPI * This)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