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