]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Disk/CdExpressPei/PeiCdExpress.c
MdeModulePkg/CdExpressPei: Add RecoveryBlockIo2Ppi support
[mirror_edk2.git] / MdeModulePkg / Universal / Disk / CdExpressPei / PeiCdExpress.c
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
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
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
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 //
166 // Find out all Block Io Ppi instances within the system
167 // Assuming all device Block Io Peims are dispatched already
168 //
169 for (BlockIoPpiInstance = 0; BlockIoPpiInstance < PEI_CD_EXPRESS_MAX_BLOCK_IO_PPI; BlockIoPpiInstance++) {
170 if (BlockIo2) {
171 Status = PeiServicesLocatePpi (
172 &gEfiPeiVirtualBlockIo2PpiGuid,
173 BlockIoPpiInstance,
174 &TempPpiDescriptor,
175 (VOID **) &BlockIo2Ppi
176 );
177 } else {
178 Status = PeiServicesLocatePpi (
179 &gEfiPeiVirtualBlockIoPpiGuid,
180 BlockIoPpiInstance,
181 &TempPpiDescriptor,
182 (VOID **) &BlockIoPpi
183 );
184 }
185 if (EFI_ERROR (Status)) {
186 //
187 // Done with all Block Io Ppis
188 //
189 break;
190 }
191
192 PeiServices = (EFI_PEI_SERVICES **) GetPeiServicesTablePointer ();
193 if (BlockIo2) {
194 Status = BlockIo2Ppi->GetNumberOfBlockDevices (
195 PeiServices,
196 BlockIo2Ppi,
197 &NumberBlockDevices
198 );
199 } else {
200 Status = BlockIoPpi->GetNumberOfBlockDevices (
201 PeiServices,
202 BlockIoPpi,
203 &NumberBlockDevices
204 );
205 }
206 if (EFI_ERROR (Status) || (NumberBlockDevices == 0)) {
207 continue;
208 }
209 //
210 // Just retrieve the first block, should emulate all blocks.
211 //
212 for (IndexBlockDevice = 1; IndexBlockDevice <= NumberBlockDevices && PrivateData->CapsuleCount < PEI_CD_EXPRESS_MAX_CAPSULE_NUMBER; IndexBlockDevice ++) {
213 if (BlockIo2) {
214 Status = BlockIo2Ppi->GetBlockDeviceMediaInfo (
215 PeiServices,
216 BlockIo2Ppi,
217 IndexBlockDevice,
218 &Media2
219 );
220 if (EFI_ERROR (Status) ||
221 !Media2.MediaPresent ||
222 ((Media2.InterfaceType != MSG_ATAPI_DP) && (Media2.InterfaceType != MSG_USB_DP)) ||
223 (Media2.BlockSize != PEI_CD_BLOCK_SIZE)
224 ) {
225 continue;
226 }
227 DEBUG ((EFI_D_INFO, "PeiCdExpress InterfaceType is %d\n", Media2.InterfaceType));
228 DEBUG ((EFI_D_INFO, "PeiCdExpress MediaPresent is %d\n", Media2.MediaPresent));
229 DEBUG ((EFI_D_INFO, "PeiCdExpress BlockSize is 0x%x\n", Media2.BlockSize));
230 } else {
231 Status = BlockIoPpi->GetBlockDeviceMediaInfo (
232 PeiServices,
233 BlockIoPpi,
234 IndexBlockDevice,
235 &Media
236 );
237 if (EFI_ERROR (Status) ||
238 !Media.MediaPresent ||
239 ((Media.DeviceType != IdeCDROM) && (Media.DeviceType != UsbMassStorage)) ||
240 (Media.BlockSize != PEI_CD_BLOCK_SIZE)
241 ) {
242 continue;
243 }
244 DEBUG ((EFI_D_INFO, "PeiCdExpress DeviceType is %d\n", Media.DeviceType));
245 DEBUG ((EFI_D_INFO, "PeiCdExpress MediaPresent is %d\n", Media.MediaPresent));
246 DEBUG ((EFI_D_INFO, "PeiCdExpress BlockSize is 0x%x\n", Media.BlockSize));
247 }
248
249 DEBUG ((EFI_D_INFO, "PeiCdExpress Status is %d\n", Status));
250
251 DEBUG ((EFI_D_INFO, "IndexBlockDevice is %d\n", IndexBlockDevice));
252 PrivateData->CapsuleData[PrivateData->CapsuleCount].IndexBlock = IndexBlockDevice;
253 if (BlockIo2) {
254 PrivateData->CapsuleData[PrivateData->CapsuleCount].BlockIo2 = BlockIo2Ppi;
255 } else {
256 PrivateData->CapsuleData[PrivateData->CapsuleCount].BlockIo = BlockIoPpi;
257 }
258 Status = FindRecoveryCapsules (PrivateData);
259 DEBUG ((EFI_D_INFO, "Status is %d\n", Status));
260
261 if (EFI_ERROR (Status)) {
262 continue;
263 }
264
265 PrivateData->CapsuleCount++;
266 }
267
268 }
269
270 return EFI_SUCCESS;
271 }
272
273 /**
274 Finds out the recovery capsule in the current volume.
275
276 @param PrivateData The private data structure that contains recovery module information.
277
278 @retval EFI_SUCCESS The recovery capsule is successfully found in the volume.
279 @retval EFI_NOT_FOUND The recovery capsule is not found in the volume.
280
281 **/
282 EFI_STATUS
283 EFIAPI
284 FindRecoveryCapsules (
285 IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData
286 )
287 {
288 EFI_STATUS Status;
289 UINTN Lba;
290 EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi;
291 EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2Ppi;
292 UINTN BufferSize;
293 UINT8 *Buffer;
294 UINT8 Type;
295 UINT8 *StandardID;
296 UINT32 RootDirLBA;
297 PEI_CD_EXPRESS_DIR_FILE_RECORD *RoorDirRecord;
298 UINTN VolumeSpaceSize;
299 BOOLEAN StartOfVolume;
300 UINTN OriginalLBA;
301 UINTN IndexBlockDevice;
302
303 Buffer = PrivateData->BlockBuffer;
304 BufferSize = PEI_CD_BLOCK_SIZE;
305
306 Lba = 16;
307 //
308 // The volume descriptor starts on Lba 16
309 //
310 IndexBlockDevice = PrivateData->CapsuleData[PrivateData->CapsuleCount].IndexBlock;
311 BlockIoPpi = PrivateData->CapsuleData[PrivateData->CapsuleCount].BlockIo;
312 BlockIo2Ppi = PrivateData->CapsuleData[PrivateData->CapsuleCount].BlockIo2;
313
314 VolumeSpaceSize = 0;
315 StartOfVolume = TRUE;
316 OriginalLBA = 16;
317
318 while (TRUE) {
319 SetMem (Buffer, BufferSize, 0);
320 if (BlockIo2Ppi != NULL) {
321 Status = BlockIo2Ppi->ReadBlocks (
322 (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
323 BlockIo2Ppi,
324 IndexBlockDevice,
325 Lba,
326 BufferSize,
327 Buffer
328 );
329 } else {
330 Status = BlockIoPpi->ReadBlocks (
331 (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
332 BlockIoPpi,
333 IndexBlockDevice,
334 Lba,
335 BufferSize,
336 Buffer
337 );
338 }
339 if (EFI_ERROR (Status)) {
340 return Status;
341 }
342
343 StandardID = (UINT8 *) (Buffer + PEI_CD_EXPRESS_STANDARD_ID_OFFSET);
344 if (!StringCmp (StandardID, (UINT8 *) PEI_CD_STANDARD_ID, PEI_CD_EXPRESS_STANDARD_ID_SIZE, TRUE)) {
345 break;
346 }
347
348 if (StartOfVolume) {
349 OriginalLBA = Lba;
350 StartOfVolume = FALSE;
351 }
352
353 Type = *(UINT8 *) (Buffer + PEI_CD_EXPRESS_VOLUME_TYPE_OFFSET);
354 if (Type == PEI_CD_EXPRESS_VOLUME_TYPE_TERMINATOR) {
355 if (VolumeSpaceSize == 0) {
356 break;
357 } else {
358 Lba = (OriginalLBA + VolumeSpaceSize);
359 VolumeSpaceSize = 0;
360 StartOfVolume = TRUE;
361 continue;
362 }
363 }
364
365 if (Type != PEI_CD_EXPRESS_VOLUME_TYPE_PRIMARY) {
366 Lba++;
367 continue;
368 }
369
370 VolumeSpaceSize = *(UINT32 *) (Buffer + PEI_CD_EXPRESS_VOLUME_SPACE_OFFSET);
371
372 RoorDirRecord = (PEI_CD_EXPRESS_DIR_FILE_RECORD *) (Buffer + PEI_CD_EXPRESS_ROOT_DIR_RECORD_OFFSET);
373 RootDirLBA = RoorDirRecord->LocationOfExtent[0];
374
375 Status = RetrieveCapsuleFileFromRoot (PrivateData, BlockIoPpi, BlockIo2Ppi, IndexBlockDevice, RootDirLBA);
376 if (!EFI_ERROR (Status)) {
377 //
378 // Just look for the first primary descriptor
379 //
380 return EFI_SUCCESS;
381 }
382
383 Lba++;
384 }
385
386 return EFI_NOT_FOUND;
387 }
388
389 /**
390 Retrieves the recovery capsule in root directory of the current volume.
391
392 @param PrivateData The private data structure that contains recovery module information.
393 @param BlockIoPpi The Block IO PPI used to access the volume.
394 @param BlockIo2Ppi The Block IO 2 PPI used to access the volume.
395 @param IndexBlockDevice The index of current block device.
396 @param Lba The starting logic block address to retrieve capsule.
397
398 @retval EFI_SUCCESS The recovery capsule is successfully found in the volume.
399 @retval EFI_NOT_FOUND The recovery capsule is not found in the volume.
400 @retval Others
401
402 **/
403 EFI_STATUS
404 EFIAPI
405 RetrieveCapsuleFileFromRoot (
406 IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData,
407 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi,
408 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2Ppi,
409 IN UINTN IndexBlockDevice,
410 IN UINT32 Lba
411 )
412 {
413 EFI_STATUS Status;
414 UINTN BufferSize;
415 UINT8 *Buffer;
416 PEI_CD_EXPRESS_DIR_FILE_RECORD *FileRecord;
417 UINTN Index;
418
419 Buffer = PrivateData->BlockBuffer;
420 BufferSize = PEI_CD_BLOCK_SIZE;
421
422 SetMem (Buffer, BufferSize, 0);
423
424 if (BlockIo2Ppi != NULL) {
425 Status = BlockIo2Ppi->ReadBlocks (
426 (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
427 BlockIo2Ppi,
428 IndexBlockDevice,
429 Lba,
430 BufferSize,
431 Buffer
432 );
433 } else {
434 Status = BlockIoPpi->ReadBlocks (
435 (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
436 BlockIoPpi,
437 IndexBlockDevice,
438 Lba,
439 BufferSize,
440 Buffer
441 );
442 }
443 if (EFI_ERROR (Status)) {
444 return Status;
445 }
446
447 while (1) {
448 FileRecord = (PEI_CD_EXPRESS_DIR_FILE_RECORD *) Buffer;
449
450 if (FileRecord->Length == 0) {
451 break;
452 }
453 //
454 // Not intend to check other flag now
455 //
456 if ((FileRecord->Flag & PEI_CD_EXPRESS_DIR_FILE_REC_FLAG_ISDIR) != 0) {
457 Buffer += FileRecord->Length;
458 continue;
459 }
460
461 for (Index = 0; Index < FileRecord->FileIDLength; Index++) {
462 if (FileRecord->FileID[Index] == ';') {
463 break;
464 }
465 }
466
467 if (Index != (sizeof (PEI_RECOVERY_FILE_NAME) - 1)) {
468 Buffer += FileRecord->Length;
469 continue;
470 }
471
472 if (!StringCmp (FileRecord->FileID, (UINT8 *) PEI_RECOVERY_FILE_NAME, sizeof (PEI_RECOVERY_FILE_NAME) - 1, FALSE)) {
473 Buffer += FileRecord->Length;
474 continue;
475 }
476
477 PrivateData->CapsuleData[PrivateData->CapsuleCount].CapsuleStartLBA = FileRecord->LocationOfExtent[0];
478 PrivateData->CapsuleData[PrivateData->CapsuleCount].CapsuleSize =
479 (
480 FileRecord->DataLength[0] /
481 PEI_CD_BLOCK_SIZE +
482 1
483 ) *
484 PEI_CD_BLOCK_SIZE;
485
486 return EFI_SUCCESS;
487 }
488
489 return EFI_NOT_FOUND;
490 }
491
492 /**
493 Returns the number of DXE capsules residing on the device.
494
495 This function searches for DXE capsules from the associated device and returns
496 the number and maximum size in bytes of the capsules discovered. Entry 1 is
497 assumed to be the highest load priority and entry N is assumed to be the lowest
498 priority.
499
500 @param[in] PeiServices General-purpose services that are available
501 to every PEIM
502 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
503 instance.
504 @param[out] NumberRecoveryCapsules Pointer to a caller-allocated UINTN. On
505 output, *NumberRecoveryCapsules contains
506 the number of recovery capsule images
507 available for retrieval from this PEIM
508 instance.
509
510 @retval EFI_SUCCESS One or more capsules were discovered.
511 @retval EFI_DEVICE_ERROR A device error occurred.
512 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
513
514 **/
515 EFI_STATUS
516 EFIAPI
517 GetNumberRecoveryCapsules (
518 IN EFI_PEI_SERVICES **PeiServices,
519 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,
520 OUT UINTN *NumberRecoveryCapsules
521 )
522 {
523 PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData;
524
525 PrivateData = PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This);
526 UpdateBlocksAndVolumes (PrivateData, TRUE);
527 UpdateBlocksAndVolumes (PrivateData, FALSE);
528 *NumberRecoveryCapsules = PrivateData->CapsuleCount;
529
530 if (*NumberRecoveryCapsules == 0) {
531 return EFI_NOT_FOUND;
532 }
533
534 return EFI_SUCCESS;
535 }
536
537 /**
538 Returns the size and type of the requested recovery capsule.
539
540 This function gets the size and type of the capsule specified by CapsuleInstance.
541
542 @param[in] PeiServices General-purpose services that are available to every PEIM
543 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
544 instance.
545 @param[in] CapsuleInstance Specifies for which capsule instance to retrieve
546 the information. This parameter must be between
547 one and the value returned by GetNumberRecoveryCapsules()
548 in NumberRecoveryCapsules.
549 @param[out] Size A pointer to a caller-allocated UINTN in which
550 the size of the requested recovery module is
551 returned.
552 @param[out] CapsuleType A pointer to a caller-allocated EFI_GUID in which
553 the type of the requested recovery capsule is
554 returned. The semantic meaning of the value
555 returned is defined by the implementation.
556
557 @retval EFI_SUCCESS One or more capsules were discovered.
558 @retval EFI_DEVICE_ERROR A device error occurred.
559 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
560
561 **/
562 EFI_STATUS
563 EFIAPI
564 GetRecoveryCapsuleInfo (
565 IN EFI_PEI_SERVICES **PeiServices,
566 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,
567 IN UINTN CapsuleInstance,
568 OUT UINTN *Size,
569 OUT EFI_GUID *CapsuleType
570 )
571 {
572 PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData;
573 UINTN NumberRecoveryCapsules;
574 EFI_STATUS Status;
575
576 Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules);
577
578 if (EFI_ERROR (Status)) {
579 return Status;
580 }
581
582 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
583 CapsuleInstance = CapsuleInstance + 1;
584 }
585
586 if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) {
587 return EFI_NOT_FOUND;
588 }
589
590 PrivateData = PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This);
591
592 *Size = PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleSize;
593 CopyMem (
594 CapsuleType,
595 &gRecoveryOnDataCdGuid,
596 sizeof (EFI_GUID)
597 );
598
599 return EFI_SUCCESS;
600 }
601
602 /**
603 Loads a DXE capsule from some media into memory.
604
605 This function, by whatever mechanism, retrieves a DXE capsule from some device
606 and loads it into memory. Note that the published interface is device neutral.
607
608 @param[in] PeiServices General-purpose services that are available
609 to every PEIM
610 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
611 instance.
612 @param[in] CapsuleInstance Specifies which capsule instance to retrieve.
613 @param[out] Buffer Specifies a caller-allocated buffer in which
614 the requested recovery capsule will be returned.
615
616 @retval EFI_SUCCESS The capsule was loaded correctly.
617 @retval EFI_DEVICE_ERROR A device error occurred.
618 @retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found.
619
620 **/
621 EFI_STATUS
622 EFIAPI
623 LoadRecoveryCapsule (
624 IN EFI_PEI_SERVICES **PeiServices,
625 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,
626 IN UINTN CapsuleInstance,
627 OUT VOID *Buffer
628 )
629 {
630 EFI_STATUS Status;
631 PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData;
632 EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi;
633 EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2Ppi;
634 UINTN NumberRecoveryCapsules;
635
636 Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules);
637
638 if (EFI_ERROR (Status)) {
639 return Status;
640 }
641
642 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
643 CapsuleInstance = CapsuleInstance + 1;
644 }
645
646 if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) {
647 return EFI_NOT_FOUND;
648 }
649
650 PrivateData = PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This);
651 BlockIoPpi = PrivateData->CapsuleData[CapsuleInstance - 1].BlockIo;
652 BlockIo2Ppi = PrivateData->CapsuleData[CapsuleInstance - 1].BlockIo2;
653
654 if (BlockIo2Ppi != NULL) {
655 Status = BlockIo2Ppi->ReadBlocks (
656 PeiServices,
657 BlockIo2Ppi,
658 PrivateData->CapsuleData[CapsuleInstance - 1].IndexBlock,
659 PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleStartLBA,
660 PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleSize,
661 Buffer
662 );
663 } else {
664 Status = BlockIoPpi->ReadBlocks (
665 PeiServices,
666 BlockIoPpi,
667 PrivateData->CapsuleData[CapsuleInstance - 1].IndexBlock,
668 PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleStartLBA,
669 PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleSize,
670 Buffer
671 );
672 }
673 return Status;
674 }
675
676 /**
677 This function compares two ASCII strings in case sensitive/insensitive way.
678
679 @param Source1 The first string.
680 @param Source2 The second string.
681 @param Size The maximum comparison length.
682 @param CaseSensitive Flag to indicate whether the comparison is case sensitive.
683
684 @retval TRUE The two strings are the same.
685 @retval FALSE The two string are not the same.
686
687 **/
688 BOOLEAN
689 StringCmp (
690 IN UINT8 *Source1,
691 IN UINT8 *Source2,
692 IN UINTN Size,
693 IN BOOLEAN CaseSensitive
694 )
695 {
696 UINTN Index;
697 UINT8 Dif;
698
699 for (Index = 0; Index < Size; Index++) {
700 if (Source1[Index] == Source2[Index]) {
701 continue;
702 }
703
704 if (!CaseSensitive) {
705 Dif = (UINT8) ((Source1[Index] > Source2[Index]) ? (Source1[Index] - Source2[Index]) : (Source2[Index] - Source1[Index]));
706 if (Dif == ('a' - 'A')) {
707 continue;
708 }
709 }
710
711 return FALSE;
712 }
713
714 return TRUE;
715 }