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