• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   Source file for CD recovery PEIM
3 
4 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
5 
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions
8 of the BSD License which accompanies this distribution.  The
9 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 "PeiCdExpress.h"
18 
19 PEI_CD_EXPRESS_PRIVATE_DATA *mPrivateData = NULL;
20 CHAR8 *mRecoveryFileName;
21 UINTN mRecoveryFileNameSize;
22 
23 /**
24   Installs the Device Recovery Module PPI, Initialize BlockIo Ppi
25   installation notification
26 
27   @param  FileHandle            The file handle of the image.
28   @param  PeiServices           General purpose services available to every PEIM.
29 
30   @retval EFI_SUCCESS           The function completed successfully.
31   @retval EFI_OUT_OF_RESOURCES  There is not enough system memory.
32 
33 **/
34 EFI_STATUS
35 EFIAPI
CdExpressPeimEntry(IN EFI_PEI_FILE_HANDLE FileHandle,IN CONST EFI_PEI_SERVICES ** PeiServices)36 CdExpressPeimEntry (
37   IN EFI_PEI_FILE_HANDLE       FileHandle,
38   IN CONST EFI_PEI_SERVICES    **PeiServices
39   )
40 {
41   EFI_STATUS                  Status;
42   PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData;
43 
44   if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
45     return EFI_SUCCESS;
46   }
47 
48   PrivateData = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (*PrivateData)));
49   if (PrivateData == NULL) {
50     return EFI_OUT_OF_RESOURCES;
51   }
52 
53   mRecoveryFileNameSize = PcdGetSize(PcdRecoveryFileName) / sizeof(CHAR16);
54   mRecoveryFileName = AllocatePool(mRecoveryFileNameSize);
55   if (mRecoveryFileName == NULL) {
56     return EFI_OUT_OF_RESOURCES;
57   }
58   Status = UnicodeStrToAsciiStrS(PcdGetPtr(PcdRecoveryFileName), mRecoveryFileName, mRecoveryFileNameSize);
59   if (EFI_ERROR(Status)) {
60     return Status;
61   }
62 
63   //
64   // Initialize Private Data (to zero, as is required by subsequent operations)
65   //
66   ZeroMem (PrivateData, sizeof (*PrivateData));
67   PrivateData->Signature    = PEI_CD_EXPRESS_PRIVATE_DATA_SIGNATURE;
68 
69   PrivateData->BlockBuffer  = AllocatePages (EFI_SIZE_TO_PAGES (PEI_CD_BLOCK_SIZE));
70   if (PrivateData->BlockBuffer == NULL) {
71     return EFI_OUT_OF_RESOURCES;
72   }
73 
74   PrivateData->CapsuleCount = 0;
75   Status = UpdateBlocksAndVolumes (PrivateData, TRUE);
76   Status = UpdateBlocksAndVolumes (PrivateData, FALSE);
77 
78   //
79   // Installs Ppi
80   //
81   PrivateData->DeviceRecoveryPpi.GetNumberRecoveryCapsules  = GetNumberRecoveryCapsules;
82   PrivateData->DeviceRecoveryPpi.GetRecoveryCapsuleInfo     = GetRecoveryCapsuleInfo;
83   PrivateData->DeviceRecoveryPpi.LoadRecoveryCapsule        = LoadRecoveryCapsule;
84 
85   PrivateData->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
86   PrivateData->PpiDescriptor.Guid  = &gEfiPeiDeviceRecoveryModulePpiGuid;
87   PrivateData->PpiDescriptor.Ppi   = &PrivateData->DeviceRecoveryPpi;
88 
89   Status = PeiServicesInstallPpi (&PrivateData->PpiDescriptor);
90   if (EFI_ERROR (Status)) {
91     return EFI_OUT_OF_RESOURCES;
92   }
93   //
94   // PrivateData is allocated now, set it to the module variable
95   //
96   mPrivateData = PrivateData;
97 
98   //
99   // Installs Block Io Ppi notification function
100   //
101   PrivateData->NotifyDescriptor.Flags =
102     (
103       EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
104     );
105   PrivateData->NotifyDescriptor.Guid    = &gEfiPeiVirtualBlockIoPpiGuid;
106   PrivateData->NotifyDescriptor.Notify  = BlockIoNotifyEntry;
107 
108   PrivateData->NotifyDescriptor2.Flags =
109     (
110       EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK |
111       EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
112     );
113   PrivateData->NotifyDescriptor2.Guid    = &gEfiPeiVirtualBlockIo2PpiGuid;
114   PrivateData->NotifyDescriptor2.Notify  = BlockIoNotifyEntry;
115 
116   return PeiServicesNotifyPpi (&PrivateData->NotifyDescriptor);
117 
118 }
119 
120 /**
121   BlockIo installation notification function.
122 
123   This function finds out all the current Block IO PPIs in the system and add them
124   into private data.
125 
126   @param  PeiServices            Indirect reference to the PEI Services Table.
127   @param  NotifyDescriptor       Address of the notification descriptor data structure.
128   @param  Ppi                    Address of the PPI that was installed.
129 
130   @retval EFI_SUCCESS            The function completes successfully.
131 
132 **/
133 EFI_STATUS
134 EFIAPI
BlockIoNotifyEntry(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_NOTIFY_DESCRIPTOR * NotifyDescriptor,IN VOID * Ppi)135 BlockIoNotifyEntry (
136   IN EFI_PEI_SERVICES           **PeiServices,
137   IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
138   IN VOID                       *Ppi
139   )
140 {
141   if (CompareGuid (NotifyDescriptor->Guid, &gEfiPeiVirtualBlockIo2PpiGuid)) {
142     UpdateBlocksAndVolumes (mPrivateData, TRUE);
143   } else {
144     UpdateBlocksAndVolumes (mPrivateData, FALSE);
145   }
146 
147   return EFI_SUCCESS;
148 }
149 
150 /**
151   Finds out all the current Block IO PPIs in the system and add them into private data.
152 
153   @param PrivateData                    The private data structure that contains recovery module information.
154   @param BlockIo2                       Boolean to show whether using BlockIo2 or BlockIo.
155 
156   @retval EFI_SUCCESS                   The blocks and volumes are updated successfully.
157 
158 **/
159 EFI_STATUS
UpdateBlocksAndVolumes(IN OUT PEI_CD_EXPRESS_PRIVATE_DATA * PrivateData,IN BOOLEAN BlockIo2)160 UpdateBlocksAndVolumes (
161   IN OUT PEI_CD_EXPRESS_PRIVATE_DATA     *PrivateData,
162   IN     BOOLEAN                         BlockIo2
163   )
164 {
165   EFI_STATUS                      Status;
166   EFI_PEI_PPI_DESCRIPTOR          *TempPpiDescriptor;
167   UINTN                           BlockIoPpiInstance;
168   EFI_PEI_RECOVERY_BLOCK_IO_PPI   *BlockIoPpi;
169   EFI_PEI_RECOVERY_BLOCK_IO2_PPI  *BlockIo2Ppi;
170   UINTN                           NumberBlockDevices;
171   UINTN                           IndexBlockDevice;
172   EFI_PEI_BLOCK_IO_MEDIA          Media;
173   EFI_PEI_BLOCK_IO2_MEDIA         Media2;
174   EFI_PEI_SERVICES                **PeiServices;
175 
176   IndexBlockDevice = 0;
177   BlockIo2Ppi      = NULL;
178   BlockIoPpi       = NULL;
179   //
180   // Find out all Block Io Ppi instances within the system
181   // Assuming all device Block Io Peims are dispatched already
182   //
183   for (BlockIoPpiInstance = 0; BlockIoPpiInstance < PEI_CD_EXPRESS_MAX_BLOCK_IO_PPI; BlockIoPpiInstance++) {
184     if (BlockIo2) {
185       Status = PeiServicesLocatePpi (
186                                 &gEfiPeiVirtualBlockIo2PpiGuid,
187                                 BlockIoPpiInstance,
188                                 &TempPpiDescriptor,
189                                 (VOID **) &BlockIo2Ppi
190                                 );
191     } else {
192       Status = PeiServicesLocatePpi (
193                                 &gEfiPeiVirtualBlockIoPpiGuid,
194                                 BlockIoPpiInstance,
195                                 &TempPpiDescriptor,
196                                 (VOID **) &BlockIoPpi
197                                 );
198     }
199     if (EFI_ERROR (Status)) {
200       //
201       // Done with all Block Io Ppis
202       //
203       break;
204     }
205 
206     PeiServices = (EFI_PEI_SERVICES  **) GetPeiServicesTablePointer ();
207     if (BlockIo2) {
208       Status = BlockIo2Ppi->GetNumberOfBlockDevices (
209                               PeiServices,
210                               BlockIo2Ppi,
211                               &NumberBlockDevices
212                               );
213     } else {
214       Status = BlockIoPpi->GetNumberOfBlockDevices (
215                             PeiServices,
216                             BlockIoPpi,
217                             &NumberBlockDevices
218                             );
219     }
220     if (EFI_ERROR (Status) || (NumberBlockDevices == 0)) {
221       continue;
222     }
223     //
224     // Just retrieve the first block, should emulate all blocks.
225     //
226     for (IndexBlockDevice = 1; IndexBlockDevice <= NumberBlockDevices && PrivateData->CapsuleCount < PEI_CD_EXPRESS_MAX_CAPSULE_NUMBER; IndexBlockDevice ++) {
227       if (BlockIo2) {
228         Status = BlockIo2Ppi->GetBlockDeviceMediaInfo (
229                                 PeiServices,
230                                 BlockIo2Ppi,
231                                 IndexBlockDevice,
232                                 &Media2
233                                 );
234         if (EFI_ERROR (Status) ||
235             !Media2.MediaPresent ||
236              ((Media2.InterfaceType != MSG_ATAPI_DP) && (Media2.InterfaceType != MSG_USB_DP)) ||
237             (Media2.BlockSize != PEI_CD_BLOCK_SIZE)
238             ) {
239           continue;
240         }
241         DEBUG ((EFI_D_INFO, "PeiCdExpress InterfaceType is %d\n", Media2.InterfaceType));
242         DEBUG ((EFI_D_INFO, "PeiCdExpress MediaPresent is %d\n", Media2.MediaPresent));
243         DEBUG ((EFI_D_INFO, "PeiCdExpress BlockSize is  0x%x\n", Media2.BlockSize));
244       } else {
245         Status = BlockIoPpi->GetBlockDeviceMediaInfo (
246                               PeiServices,
247                               BlockIoPpi,
248                               IndexBlockDevice,
249                               &Media
250                               );
251         if (EFI_ERROR (Status) ||
252             !Media.MediaPresent ||
253              ((Media.DeviceType != IdeCDROM) && (Media.DeviceType != UsbMassStorage)) ||
254             (Media.BlockSize != PEI_CD_BLOCK_SIZE)
255             ) {
256           continue;
257         }
258         DEBUG ((EFI_D_INFO, "PeiCdExpress DeviceType is %d\n", Media.DeviceType));
259         DEBUG ((EFI_D_INFO, "PeiCdExpress MediaPresent is %d\n", Media.MediaPresent));
260         DEBUG ((EFI_D_INFO, "PeiCdExpress BlockSize is  0x%x\n", Media.BlockSize));
261       }
262 
263       DEBUG ((EFI_D_INFO, "PeiCdExpress Status is %d\n", Status));
264 
265       DEBUG ((EFI_D_INFO, "IndexBlockDevice is %d\n", IndexBlockDevice));
266       PrivateData->CapsuleData[PrivateData->CapsuleCount].IndexBlock = IndexBlockDevice;
267       if (BlockIo2) {
268         PrivateData->CapsuleData[PrivateData->CapsuleCount].BlockIo2 = BlockIo2Ppi;
269       } else {
270         PrivateData->CapsuleData[PrivateData->CapsuleCount].BlockIo  = BlockIoPpi;
271       }
272       Status = FindRecoveryCapsules (PrivateData);
273       DEBUG ((EFI_D_INFO, "Status is %d\n", Status));
274 
275       if (EFI_ERROR (Status)) {
276         continue;
277       }
278 
279       PrivateData->CapsuleCount++;
280     }
281 
282   }
283 
284   return EFI_SUCCESS;
285 }
286 
287 /**
288   Finds out the recovery capsule in the current volume.
289 
290   @param PrivateData                    The private data structure that contains recovery module information.
291 
292   @retval EFI_SUCCESS                   The recovery capsule is successfully found in the volume.
293   @retval EFI_NOT_FOUND                 The recovery capsule is not found in the volume.
294 
295 **/
296 EFI_STATUS
297 EFIAPI
FindRecoveryCapsules(IN OUT PEI_CD_EXPRESS_PRIVATE_DATA * PrivateData)298 FindRecoveryCapsules (
299   IN OUT PEI_CD_EXPRESS_PRIVATE_DATA            *PrivateData
300   )
301 {
302   EFI_STATUS                      Status;
303   UINTN                           Lba;
304   EFI_PEI_RECOVERY_BLOCK_IO_PPI   *BlockIoPpi;
305   EFI_PEI_RECOVERY_BLOCK_IO2_PPI  *BlockIo2Ppi;
306   UINTN                           BufferSize;
307   UINT8                           *Buffer;
308   UINT8                           Type;
309   UINT8                           *StandardID;
310   UINT32                          RootDirLBA;
311   PEI_CD_EXPRESS_DIR_FILE_RECORD  *RoorDirRecord;
312   UINTN                           VolumeSpaceSize;
313   BOOLEAN                         StartOfVolume;
314   UINTN                           OriginalLBA;
315   UINTN                           IndexBlockDevice;
316 
317   Buffer      = PrivateData->BlockBuffer;
318   BufferSize  = PEI_CD_BLOCK_SIZE;
319 
320   Lba         = 16;
321   //
322   // The volume descriptor starts on Lba 16
323   //
324   IndexBlockDevice = PrivateData->CapsuleData[PrivateData->CapsuleCount].IndexBlock;
325   BlockIoPpi       = PrivateData->CapsuleData[PrivateData->CapsuleCount].BlockIo;
326   BlockIo2Ppi      = PrivateData->CapsuleData[PrivateData->CapsuleCount].BlockIo2;
327 
328   VolumeSpaceSize = 0;
329   StartOfVolume   = TRUE;
330   OriginalLBA     = 16;
331 
332   while (TRUE) {
333     SetMem (Buffer, BufferSize, 0);
334     if (BlockIo2Ppi != NULL) {
335       Status = BlockIo2Ppi->ReadBlocks (
336                             (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
337                             BlockIo2Ppi,
338                             IndexBlockDevice,
339                             Lba,
340                             BufferSize,
341                             Buffer
342                             );
343     } else {
344       Status = BlockIoPpi->ReadBlocks (
345                             (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
346                             BlockIoPpi,
347                             IndexBlockDevice,
348                             Lba,
349                             BufferSize,
350                             Buffer
351                             );
352     }
353     if (EFI_ERROR (Status)) {
354       return Status;
355     }
356 
357     StandardID = (UINT8 *) (Buffer + PEI_CD_EXPRESS_STANDARD_ID_OFFSET);
358     if (!StringCmp (StandardID, (UINT8 *) PEI_CD_STANDARD_ID, PEI_CD_EXPRESS_STANDARD_ID_SIZE, TRUE)) {
359       break;
360     }
361 
362     if (StartOfVolume) {
363       OriginalLBA   = Lba;
364       StartOfVolume = FALSE;
365     }
366 
367     Type = *(UINT8 *) (Buffer + PEI_CD_EXPRESS_VOLUME_TYPE_OFFSET);
368     if (Type == PEI_CD_EXPRESS_VOLUME_TYPE_TERMINATOR) {
369       if (VolumeSpaceSize == 0) {
370         break;
371       } else {
372         Lba             = (OriginalLBA + VolumeSpaceSize);
373         VolumeSpaceSize = 0;
374         StartOfVolume   = TRUE;
375         continue;
376       }
377     }
378 
379     if (Type != PEI_CD_EXPRESS_VOLUME_TYPE_PRIMARY) {
380       Lba++;
381       continue;
382     }
383 
384     VolumeSpaceSize = *(UINT32 *) (Buffer + PEI_CD_EXPRESS_VOLUME_SPACE_OFFSET);
385 
386     RoorDirRecord   = (PEI_CD_EXPRESS_DIR_FILE_RECORD *) (Buffer + PEI_CD_EXPRESS_ROOT_DIR_RECORD_OFFSET);
387     RootDirLBA      = RoorDirRecord->LocationOfExtent[0];
388 
389     Status          = RetrieveCapsuleFileFromRoot (PrivateData, BlockIoPpi, BlockIo2Ppi, IndexBlockDevice, RootDirLBA);
390     if (!EFI_ERROR (Status)) {
391       //
392       // Just look for the first primary descriptor
393       //
394       return EFI_SUCCESS;
395     }
396 
397     Lba++;
398   }
399 
400   return EFI_NOT_FOUND;
401 }
402 
403 /**
404   Retrieves the recovery capsule in root directory of the current volume.
405 
406   @param PrivateData                    The private data structure that contains recovery module information.
407   @param BlockIoPpi                     The Block IO PPI used to access the volume.
408   @param BlockIo2Ppi                    The Block IO 2 PPI used to access the volume.
409   @param IndexBlockDevice               The index of current block device.
410   @param Lba                            The starting logic block address to retrieve capsule.
411 
412   @retval EFI_SUCCESS                   The recovery capsule is successfully found in the volume.
413   @retval EFI_NOT_FOUND                 The recovery capsule is not found in the volume.
414   @retval Others
415 
416 **/
417 EFI_STATUS
418 EFIAPI
RetrieveCapsuleFileFromRoot(IN OUT PEI_CD_EXPRESS_PRIVATE_DATA * PrivateData,IN EFI_PEI_RECOVERY_BLOCK_IO_PPI * BlockIoPpi,IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI * BlockIo2Ppi,IN UINTN IndexBlockDevice,IN UINT32 Lba)419 RetrieveCapsuleFileFromRoot (
420   IN OUT PEI_CD_EXPRESS_PRIVATE_DATA        *PrivateData,
421   IN EFI_PEI_RECOVERY_BLOCK_IO_PPI          *BlockIoPpi,
422   IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI         *BlockIo2Ppi,
423   IN UINTN                                  IndexBlockDevice,
424   IN UINT32                                 Lba
425   )
426 {
427   EFI_STATUS                      Status;
428   UINTN                           BufferSize;
429   UINT8                           *Buffer;
430   PEI_CD_EXPRESS_DIR_FILE_RECORD  *FileRecord;
431   UINTN                           Index;
432 
433   Buffer      = PrivateData->BlockBuffer;
434   BufferSize  = PEI_CD_BLOCK_SIZE;
435 
436   SetMem (Buffer, BufferSize, 0);
437 
438   if (BlockIo2Ppi != NULL) {
439     Status = BlockIo2Ppi->ReadBlocks (
440                           (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
441                           BlockIo2Ppi,
442                           IndexBlockDevice,
443                           Lba,
444                           BufferSize,
445                           Buffer
446                           );
447   } else {
448     Status = BlockIoPpi->ReadBlocks (
449                           (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
450                           BlockIoPpi,
451                           IndexBlockDevice,
452                           Lba,
453                           BufferSize,
454                           Buffer
455                           );
456   }
457   if (EFI_ERROR (Status)) {
458     return Status;
459   }
460 
461   while (1) {
462     FileRecord = (PEI_CD_EXPRESS_DIR_FILE_RECORD *) Buffer;
463 
464     if (FileRecord->Length == 0) {
465       break;
466     }
467     //
468     // Not intend to check other flag now
469     //
470     if ((FileRecord->Flag & PEI_CD_EXPRESS_DIR_FILE_REC_FLAG_ISDIR) != 0) {
471       Buffer += FileRecord->Length;
472       continue;
473     }
474 
475     for (Index = 0; Index < FileRecord->FileIDLength; Index++) {
476       if (FileRecord->FileID[Index] == ';') {
477         break;
478       }
479     }
480 
481     if (Index != mRecoveryFileNameSize - 1) {
482       Buffer += FileRecord->Length;
483       continue;
484     }
485 
486     if (!StringCmp (FileRecord->FileID, (UINT8 *)mRecoveryFileName, mRecoveryFileNameSize - 1, FALSE)) {
487       Buffer += FileRecord->Length;
488       continue;
489     }
490 
491     PrivateData->CapsuleData[PrivateData->CapsuleCount].CapsuleStartLBA = FileRecord->LocationOfExtent[0];
492     PrivateData->CapsuleData[PrivateData->CapsuleCount].CapsuleBlockAlignedSize =
493       (
494         FileRecord->DataLength[0] /
495         PEI_CD_BLOCK_SIZE +
496         1
497       ) *
498       PEI_CD_BLOCK_SIZE;
499     PrivateData->CapsuleData[PrivateData->CapsuleCount].CapsuleSize = FileRecord->DataLength[0];
500 
501     return EFI_SUCCESS;
502   }
503 
504   return EFI_NOT_FOUND;
505 }
506 
507 /**
508   Returns the number of DXE capsules residing on the device.
509 
510   This function searches for DXE capsules from the associated device and returns
511   the number and maximum size in bytes of the capsules discovered. Entry 1 is
512   assumed to be the highest load priority and entry N is assumed to be the lowest
513   priority.
514 
515   @param[in]  PeiServices              General-purpose services that are available
516                                        to every PEIM
517   @param[in]  This                     Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
518                                        instance.
519   @param[out] NumberRecoveryCapsules   Pointer to a caller-allocated UINTN. On
520                                        output, *NumberRecoveryCapsules contains
521                                        the number of recovery capsule images
522                                        available for retrieval from this PEIM
523                                        instance.
524 
525   @retval EFI_SUCCESS        One or more capsules were discovered.
526   @retval EFI_DEVICE_ERROR   A device error occurred.
527   @retval EFI_NOT_FOUND      A recovery DXE capsule cannot be found.
528 
529 **/
530 EFI_STATUS
531 EFIAPI
GetNumberRecoveryCapsules(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI * This,OUT UINTN * NumberRecoveryCapsules)532 GetNumberRecoveryCapsules (
533   IN EFI_PEI_SERVICES                               **PeiServices,
534   IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI             *This,
535   OUT UINTN                                         *NumberRecoveryCapsules
536   )
537 {
538   PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData;
539 
540   PrivateData = PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This);
541   UpdateBlocksAndVolumes (PrivateData, TRUE);
542   UpdateBlocksAndVolumes (PrivateData, FALSE);
543   *NumberRecoveryCapsules = PrivateData->CapsuleCount;
544 
545   if (*NumberRecoveryCapsules == 0) {
546     return EFI_NOT_FOUND;
547   }
548 
549   return EFI_SUCCESS;
550 }
551 
552 /**
553   Returns the size and type of the requested recovery capsule.
554 
555   This function gets the size and type of the capsule specified by CapsuleInstance.
556 
557   @param[in]  PeiServices       General-purpose services that are available to every PEIM
558   @param[in]  This              Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
559                                 instance.
560   @param[in]  CapsuleInstance   Specifies for which capsule instance to retrieve
561                                 the information.  This parameter must be between
562                                 one and the value returned by GetNumberRecoveryCapsules()
563                                 in NumberRecoveryCapsules.
564   @param[out] Size              A pointer to a caller-allocated UINTN in which
565                                 the size of the requested recovery module is
566                                 returned.
567   @param[out] CapsuleType       A pointer to a caller-allocated EFI_GUID in which
568                                 the type of the requested recovery capsule is
569                                 returned.  The semantic meaning of the value
570                                 returned is defined by the implementation.
571 
572   @retval EFI_SUCCESS        One or more capsules were discovered.
573   @retval EFI_DEVICE_ERROR   A device error occurred.
574   @retval EFI_NOT_FOUND      A recovery DXE capsule cannot be found.
575 
576 **/
577 EFI_STATUS
578 EFIAPI
GetRecoveryCapsuleInfo(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI * This,IN UINTN CapsuleInstance,OUT UINTN * Size,OUT EFI_GUID * CapsuleType)579 GetRecoveryCapsuleInfo (
580   IN  EFI_PEI_SERVICES                              **PeiServices,
581   IN  EFI_PEI_DEVICE_RECOVERY_MODULE_PPI            *This,
582   IN  UINTN                                         CapsuleInstance,
583   OUT UINTN                                         *Size,
584   OUT EFI_GUID                                      *CapsuleType
585   )
586 {
587   PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData;
588   UINTN                       NumberRecoveryCapsules;
589   EFI_STATUS                  Status;
590 
591   Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules);
592 
593   if (EFI_ERROR (Status)) {
594     return Status;
595   }
596 
597   if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
598     CapsuleInstance = CapsuleInstance + 1;
599   }
600 
601   if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) {
602     return EFI_NOT_FOUND;
603   }
604 
605   PrivateData = PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This);
606 
607   *Size = PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleSize;
608   CopyMem (
609     CapsuleType,
610     &gRecoveryOnDataCdGuid,
611     sizeof (EFI_GUID)
612     );
613 
614   return EFI_SUCCESS;
615 }
616 
617 /**
618   Loads a DXE capsule from some media into memory.
619 
620   This function, by whatever mechanism, retrieves a DXE capsule from some device
621   and loads it into memory. Note that the published interface is device neutral.
622 
623   @param[in]     PeiServices       General-purpose services that are available
624                                    to every PEIM
625   @param[in]     This              Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
626                                    instance.
627   @param[in]     CapsuleInstance   Specifies which capsule instance to retrieve.
628   @param[out]    Buffer            Specifies a caller-allocated buffer in which
629                                    the requested recovery capsule will be returned.
630 
631   @retval EFI_SUCCESS        The capsule was loaded correctly.
632   @retval EFI_DEVICE_ERROR   A device error occurred.
633   @retval EFI_NOT_FOUND      A requested recovery DXE capsule cannot be found.
634 
635 **/
636 EFI_STATUS
637 EFIAPI
LoadRecoveryCapsule(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI * This,IN UINTN CapsuleInstance,OUT VOID * Buffer)638 LoadRecoveryCapsule (
639   IN EFI_PEI_SERVICES                             **PeiServices,
640   IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI           *This,
641   IN UINTN                                        CapsuleInstance,
642   OUT VOID                                        *Buffer
643   )
644 {
645   EFI_STATUS                      Status;
646   PEI_CD_EXPRESS_PRIVATE_DATA     *PrivateData;
647   EFI_PEI_RECOVERY_BLOCK_IO_PPI   *BlockIoPpi;
648   EFI_PEI_RECOVERY_BLOCK_IO2_PPI  *BlockIo2Ppi;
649   UINTN                           NumberRecoveryCapsules;
650 
651   Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules);
652 
653   if (EFI_ERROR (Status)) {
654     return Status;
655   }
656 
657   if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
658     CapsuleInstance = CapsuleInstance + 1;
659   }
660 
661   if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) {
662     return EFI_NOT_FOUND;
663   }
664 
665   PrivateData = PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This);
666   BlockIoPpi  = PrivateData->CapsuleData[CapsuleInstance - 1].BlockIo;
667   BlockIo2Ppi = PrivateData->CapsuleData[CapsuleInstance - 1].BlockIo2;
668 
669   if (BlockIo2Ppi != NULL) {
670     Status = BlockIo2Ppi->ReadBlocks (
671                           PeiServices,
672                           BlockIo2Ppi,
673                           PrivateData->CapsuleData[CapsuleInstance - 1].IndexBlock,
674                           PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleStartLBA,
675                           PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleBlockAlignedSize,
676                           Buffer
677                           );
678   } else {
679     Status = BlockIoPpi->ReadBlocks (
680                           PeiServices,
681                           BlockIoPpi,
682                           PrivateData->CapsuleData[CapsuleInstance - 1].IndexBlock,
683                           PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleStartLBA,
684                           PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleBlockAlignedSize,
685                           Buffer
686                           );
687   }
688   return Status;
689 }
690 
691 /**
692   This function compares two ASCII strings in case sensitive/insensitive way.
693 
694   @param  Source1           The first string.
695   @param  Source2           The second string.
696   @param  Size              The maximum comparison length.
697   @param  CaseSensitive     Flag to indicate whether the comparison is case sensitive.
698 
699   @retval TRUE              The two strings are the same.
700   @retval FALSE             The two string are not the same.
701 
702 **/
703 BOOLEAN
StringCmp(IN UINT8 * Source1,IN UINT8 * Source2,IN UINTN Size,IN BOOLEAN CaseSensitive)704 StringCmp (
705   IN UINT8      *Source1,
706   IN UINT8      *Source2,
707   IN UINTN      Size,
708   IN BOOLEAN    CaseSensitive
709   )
710 {
711   UINTN Index;
712   UINT8 Dif;
713 
714   for (Index = 0; Index < Size; Index++) {
715     if (Source1[Index] == Source2[Index]) {
716       continue;
717     }
718 
719     if (!CaseSensitive) {
720       Dif = (UINT8) ((Source1[Index] > Source2[Index]) ? (Source1[Index] - Source2[Index]) : (Source2[Index] - Source1[Index]));
721       if (Dif == ('a' - 'A')) {
722         continue;
723       }
724     }
725 
726     return FALSE;
727   }
728 
729   return TRUE;
730 }
731