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