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