--- /dev/null
+/** @file\r
+ Source file for CD recovery PEIM\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "PeiCdExpress.h"\r
+\r
+PEI_CD_EXPRESS_PRIVATE_DATA *mPrivateData = NULL;\r
+\r
+/**\r
+ Installs the Device Recovery Module PPI, Initialize BlockIo Ppi \r
+ installation notification\r
+\r
+ @param FileHandle The file handle of the image.\r
+ @param PeiServices General purpose services available to every PEIM.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CdExpressPeimEntry (\r
+ IN EFI_PEI_FILE_HANDLE FileHandle,\r
+ IN CONST EFI_PEI_SERVICES **PeiServices\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData;\r
+\r
+ if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ PrivateData = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (*PrivateData)));\r
+ if (PrivateData == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Initialize Private Data (to zero, as is required by subsequent operations)\r
+ //\r
+ ZeroMem (PrivateData, sizeof (*PrivateData));\r
+ PrivateData->Signature = PEI_CD_EXPRESS_PRIVATE_DATA_SIGNATURE;\r
+\r
+ PrivateData->BlockBuffer = AllocatePages (EFI_SIZE_TO_PAGES (PEI_CD_BLOCK_SIZE));\r
+ if (PrivateData->BlockBuffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ PrivateData->CapsuleCount = 0;\r
+ Status = UpdateBlocksAndVolumes (PrivateData);\r
+\r
+ //\r
+ // Installs Ppi\r
+ //\r
+ PrivateData->DeviceRecoveryPpi.GetNumberRecoveryCapsules = GetNumberRecoveryCapsules;\r
+ PrivateData->DeviceRecoveryPpi.GetRecoveryCapsuleInfo = GetRecoveryCapsuleInfo;\r
+ PrivateData->DeviceRecoveryPpi.LoadRecoveryCapsule = LoadRecoveryCapsule;\r
+\r
+ PrivateData->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);\r
+ PrivateData->PpiDescriptor.Guid = &gEfiPeiDeviceRecoveryModulePpiGuid;\r
+ PrivateData->PpiDescriptor.Ppi = &PrivateData->DeviceRecoveryPpi;\r
+\r
+ Status = PeiServicesInstallPpi (&PrivateData->PpiDescriptor);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // PrivateData is allocated now, set it to the module variable\r
+ //\r
+ mPrivateData = PrivateData;\r
+\r
+ //\r
+ // Installs Block Io Ppi notification function\r
+ //\r
+ PrivateData->NotifyDescriptor.Flags =\r
+ (\r
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK |\r
+ EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST\r
+ );\r
+ PrivateData->NotifyDescriptor.Guid = &gEfiPeiVirtualBlockIoPpiGuid;\r
+ PrivateData->NotifyDescriptor.Notify = BlockIoNotifyEntry;\r
+ return PeiServicesNotifyPpi (&PrivateData->NotifyDescriptor);\r
+\r
+}\r
+\r
+/**\r
+ BlockIo installation notification function. \r
+ \r
+ This function finds out all the current Block IO PPIs in the system and add them\r
+ into private data.\r
+\r
+ @param PeiServices Indirect reference to the PEI Services Table.\r
+ @param NotifyDescriptor Address of the notification descriptor data structure.\r
+ @param Ppi Address of the PPI that was installed.\r
+\r
+ @retval EFI_SUCCESS The function completes successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BlockIoNotifyEntry (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
+ IN VOID *Ppi\r
+ )\r
+{\r
+ UpdateBlocksAndVolumes (mPrivateData);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Finds out all the current Block IO PPIs in the system and add them into private data.\r
+\r
+ @param PrivateData The private data structure that contains recovery module information.\r
+\r
+ @retval EFI_SUCCESS The blocks and volumes are updated successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+UpdateBlocksAndVolumes (\r
+ IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PEI_PPI_DESCRIPTOR *TempPpiDescriptor;\r
+ UINTN BlockIoPpiInstance;\r
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi;\r
+ UINTN NumberBlockDevices;\r
+ UINTN IndexBlockDevice;\r
+ EFI_PEI_BLOCK_IO_MEDIA Media;\r
+ EFI_PEI_SERVICES **PeiServices;\r
+\r
+ IndexBlockDevice = 0;\r
+ //\r
+ // Find out all Block Io Ppi instances within the system\r
+ // Assuming all device Block Io Peims are dispatched already\r
+ //\r
+ for (BlockIoPpiInstance = 0; BlockIoPpiInstance < PEI_CD_EXPRESS_MAX_BLOCK_IO_PPI; BlockIoPpiInstance++) {\r
+ Status = PeiServicesLocatePpi (\r
+ &gEfiPeiVirtualBlockIoPpiGuid,\r
+ BlockIoPpiInstance,\r
+ &TempPpiDescriptor,\r
+ (VOID **) &BlockIoPpi\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Done with all Block Io Ppis\r
+ //\r
+ break;\r
+ }\r
+\r
+ PeiServices = (EFI_PEI_SERVICES **) GetPeiServicesTablePointer ();\r
+ Status = BlockIoPpi->GetNumberOfBlockDevices (\r
+ PeiServices,\r
+ BlockIoPpi,\r
+ &NumberBlockDevices\r
+ );\r
+ if (EFI_ERROR (Status) || (NumberBlockDevices == 0)) {\r
+ continue;\r
+ }\r
+ //\r
+ // Just retrieve the first block, should emulate all blocks.\r
+ //\r
+ for (IndexBlockDevice = 1; IndexBlockDevice <= NumberBlockDevices && PrivateData->CapsuleCount < PEI_CD_EXPRESS_MAX_CAPSULE_NUMBER; IndexBlockDevice ++) {\r
+ Status = BlockIoPpi->GetBlockDeviceMediaInfo (\r
+ PeiServices,\r
+ BlockIoPpi,\r
+ IndexBlockDevice,\r
+ &Media\r
+ );\r
+ if (EFI_ERROR (Status) ||\r
+ !Media.MediaPresent ||\r
+ ((Media.DeviceType != IdeCDROM) && (Media.DeviceType != UsbMassStorage)) ||\r
+ (Media.BlockSize != PEI_CD_BLOCK_SIZE)\r
+ ) {\r
+ continue;\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "PeiCdExpress DeviceType is %d\n", Media.DeviceType));\r
+ DEBUG ((EFI_D_INFO, "PeiCdExpress MediaPresent is %d\n", Media.MediaPresent));\r
+ DEBUG ((EFI_D_INFO, "PeiCdExpress BlockSize is 0x%x\n", Media.BlockSize));\r
+ DEBUG ((EFI_D_INFO, "PeiCdExpress Status is %d\n", Status));\r
+\r
+ DEBUG ((EFI_D_INFO, "IndexBlockDevice is %d\n", IndexBlockDevice));\r
+ PrivateData->CapsuleData[PrivateData->CapsuleCount].IndexBlock = IndexBlockDevice; \r
+ PrivateData->CapsuleData[PrivateData->CapsuleCount].BlockIo = BlockIoPpi;\r
+ Status = FindRecoveryCapsules (PrivateData);\r
+ DEBUG ((EFI_D_INFO, "Status is %d\n", Status));\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+ \r
+ PrivateData->CapsuleCount++;\r
+ }\r
+\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Finds out the recovery capsule in the current volume.\r
+\r
+ @param PrivateData The private data structure that contains recovery module information.\r
+\r
+ @retval EFI_SUCCESS The recovery capsule is successfully found in the volume.\r
+ @retval EFI_NOT_FOUND The recovery capsule is not found in the volume.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FindRecoveryCapsules (\r
+ IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Lba;\r
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi;\r
+ UINTN BufferSize;\r
+ UINT8 *Buffer;\r
+ UINT8 Type;\r
+ UINT8 *StandardID;\r
+ UINT32 RootDirLBA;\r
+ PEI_CD_EXPRESS_DIR_FILE_RECORD *RoorDirRecord;\r
+ UINTN VolumeSpaceSize;\r
+ BOOLEAN StartOfVolume;\r
+ UINTN OriginalLBA;\r
+ UINTN IndexBlockDevice;\r
+\r
+ Buffer = PrivateData->BlockBuffer;\r
+ BufferSize = PEI_CD_BLOCK_SIZE;\r
+\r
+ Lba = 16;\r
+ //\r
+ // The volume descriptor starts on Lba 16\r
+ //\r
+ IndexBlockDevice = PrivateData->CapsuleData[PrivateData->CapsuleCount].IndexBlock;\r
+ BlockIoPpi = PrivateData->CapsuleData[PrivateData->CapsuleCount].BlockIo;\r
+\r
+ VolumeSpaceSize = 0;\r
+ StartOfVolume = TRUE;\r
+ OriginalLBA = 16;\r
+\r
+ while (TRUE) {\r
+ SetMem (Buffer, BufferSize, 0);\r
+ Status = BlockIoPpi->ReadBlocks (\r
+ PrivateData->PeiServices,\r
+ BlockIoPpi,\r
+ IndexBlockDevice,\r
+ Lba,\r
+ BufferSize,\r
+ Buffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ StandardID = (UINT8 *) (Buffer + PEI_CD_EXPRESS_STANDARD_ID_OFFSET);\r
+ if (!StringCmp (StandardID, (UINT8 *) PEI_CD_STANDARD_ID, PEI_CD_EXPRESS_STANDARD_ID_SIZE, TRUE)) {\r
+ break;\r
+ }\r
+\r
+ if (StartOfVolume) {\r
+ OriginalLBA = Lba;\r
+ StartOfVolume = FALSE;\r
+ }\r
+\r
+ Type = *(UINT8 *) (Buffer + PEI_CD_EXPRESS_VOLUME_TYPE_OFFSET);\r
+ if (Type == PEI_CD_EXPRESS_VOLUME_TYPE_TERMINATOR) {\r
+ if (VolumeSpaceSize == 0) {\r
+ break;\r
+ } else {\r
+ Lba = (OriginalLBA + VolumeSpaceSize);\r
+ VolumeSpaceSize = 0;\r
+ StartOfVolume = TRUE;\r
+ continue;\r
+ }\r
+ }\r
+\r
+ if (Type != PEI_CD_EXPRESS_VOLUME_TYPE_PRIMARY) {\r
+ Lba++;\r
+ continue;\r
+ }\r
+\r
+ VolumeSpaceSize = *(UINT32 *) (Buffer + PEI_CD_EXPRESS_VOLUME_SPACE_OFFSET);\r
+\r
+ RoorDirRecord = (PEI_CD_EXPRESS_DIR_FILE_RECORD *) (Buffer + PEI_CD_EXPRESS_ROOT_DIR_RECORD_OFFSET);\r
+ RootDirLBA = RoorDirRecord->LocationOfExtent[0];\r
+\r
+ Status = RetrieveCapsuleFileFromRoot (PrivateData, BlockIoPpi, IndexBlockDevice, RootDirLBA);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Just look for the first primary descriptor\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Lba++;\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+ Retrieves the recovery capsule in root directory of the current volume.\r
+\r
+ @param PrivateData The private data structure that contains recovery module information.\r
+ @param BlockIoPpi The Block IO PPI used to access the volume.\r
+ @param IndexBlockDevice The index of current block device.\r
+ @param Lba The starting logic block address to retrieve capsule.\r
+\r
+ @retval EFI_SUCCESS The recovery capsule is successfully found in the volume.\r
+ @retval EFI_NOT_FOUND The recovery capsule is not found in the volume.\r
+ @retval Others \r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RetrieveCapsuleFileFromRoot (\r
+ IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi,\r
+ IN UINTN IndexBlockDevice,\r
+ IN UINT32 Lba\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN BufferSize;\r
+ UINT8 *Buffer;\r
+ PEI_CD_EXPRESS_DIR_FILE_RECORD *FileRecord;\r
+ UINTN Index;\r
+\r
+ Buffer = PrivateData->BlockBuffer;\r
+ BufferSize = PEI_CD_BLOCK_SIZE;\r
+\r
+ SetMem (Buffer, BufferSize, 0);\r
+\r
+ Status = BlockIoPpi->ReadBlocks (\r
+ PrivateData->PeiServices,\r
+ BlockIoPpi,\r
+ IndexBlockDevice,\r
+ Lba,\r
+ BufferSize,\r
+ Buffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ while (1) {\r
+ FileRecord = (PEI_CD_EXPRESS_DIR_FILE_RECORD *) Buffer;\r
+\r
+ if (FileRecord->Length == 0) {\r
+ break;\r
+ }\r
+ //\r
+ // Not intend to check other flag now\r
+ //\r
+ if ((FileRecord->Flag & PEI_CD_EXPRESS_DIR_FILE_REC_FLAG_ISDIR) != 0) {\r
+ Buffer += FileRecord->Length;\r
+ continue;\r
+ }\r
+\r
+ for (Index = 0; Index < FileRecord->FileIDLength; Index++) {\r
+ if (FileRecord->FileID[Index] == ';') {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Index != (sizeof (PEI_RECOVERY_FILE_NAME) - 1)) {\r
+ Buffer += FileRecord->Length;\r
+ continue;\r
+ }\r
+\r
+ if (!StringCmp (FileRecord->FileID, (UINT8 *) PEI_RECOVERY_FILE_NAME, sizeof (PEI_RECOVERY_FILE_NAME) - 1, FALSE)) {\r
+ Buffer += FileRecord->Length;\r
+ continue;\r
+ }\r
+\r
+ PrivateData->CapsuleData[PrivateData->CapsuleCount].CapsuleStartLBA = FileRecord->LocationOfExtent[0];\r
+ PrivateData->CapsuleData[PrivateData->CapsuleCount].CapsuleSize =\r
+ (\r
+ FileRecord->DataLength[0] /\r
+ PEI_CD_BLOCK_SIZE +\r
+ 1\r
+ ) *\r
+ PEI_CD_BLOCK_SIZE;\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+ Returns the number of DXE capsules residing on the device.\r
+\r
+ This function searches for DXE capsules from the associated device and returns\r
+ the number and maximum size in bytes of the capsules discovered. Entry 1 is \r
+ assumed to be the highest load priority and entry N is assumed to be the lowest \r
+ priority.\r
+\r
+ @param[in] PeiServices General-purpose services that are available \r
+ to every PEIM\r
+ @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI\r
+ instance.\r
+ @param[out] NumberRecoveryCapsules Pointer to a caller-allocated UINTN. On \r
+ output, *NumberRecoveryCapsules contains \r
+ the number of recovery capsule images \r
+ available for retrieval from this PEIM \r
+ instance.\r
+\r
+ @retval EFI_SUCCESS One or more capsules were discovered.\r
+ @retval EFI_DEVICE_ERROR A device error occurred.\r
+ @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetNumberRecoveryCapsules (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,\r
+ OUT UINTN *NumberRecoveryCapsules\r
+ )\r
+{\r
+ PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData;\r
+\r
+ PrivateData = PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This);\r
+ UpdateBlocksAndVolumes (PrivateData);\r
+ *NumberRecoveryCapsules = PrivateData->CapsuleCount;\r
+\r
+ if (*NumberRecoveryCapsules == 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Returns the size and type of the requested recovery capsule.\r
+\r
+ This function gets the size and type of the capsule specified by CapsuleInstance.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to every PEIM\r
+ @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI \r
+ instance.\r
+ @param[in] CapsuleInstance Specifies for which capsule instance to retrieve \r
+ the information. This parameter must be between \r
+ one and the value returned by GetNumberRecoveryCapsules() \r
+ in NumberRecoveryCapsules.\r
+ @param[out] Size A pointer to a caller-allocated UINTN in which \r
+ the size of the requested recovery module is \r
+ returned.\r
+ @param[out] CapsuleType A pointer to a caller-allocated EFI_GUID in which \r
+ the type of the requested recovery capsule is \r
+ returned. The semantic meaning of the value \r
+ returned is defined by the implementation.\r
+\r
+ @retval EFI_SUCCESS One or more capsules were discovered.\r
+ @retval EFI_DEVICE_ERROR A device error occurred.\r
+ @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetRecoveryCapsuleInfo (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,\r
+ IN UINTN CapsuleInstance,\r
+ OUT UINTN *Size,\r
+ OUT EFI_GUID *CapsuleType\r
+ )\r
+{\r
+ PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData;\r
+ UINTN NumberRecoveryCapsules;\r
+ EFI_STATUS Status;\r
+\r
+ Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {\r
+ CapsuleInstance = CapsuleInstance + 1;\r
+ }\r
+\r
+ if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ PrivateData = PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ *Size = PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleSize;\r
+ CopyMem (\r
+ CapsuleType,\r
+ &gRecoveryOnDataCdGuid,\r
+ sizeof (EFI_GUID)\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Loads a DXE capsule from some media into memory.\r
+\r
+ This function, by whatever mechanism, retrieves a DXE capsule from some device\r
+ and loads it into memory. Note that the published interface is device neutral.\r
+\r
+ @param[in] PeiServices General-purpose services that are available \r
+ to every PEIM\r
+ @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI\r
+ instance.\r
+ @param[in] CapsuleInstance Specifies which capsule instance to retrieve.\r
+ @param[out] Buffer Specifies a caller-allocated buffer in which \r
+ the requested recovery capsule will be returned.\r
+\r
+ @retval EFI_SUCCESS The capsule was loaded correctly.\r
+ @retval EFI_DEVICE_ERROR A device error occurred.\r
+ @retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LoadRecoveryCapsule (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,\r
+ IN UINTN CapsuleInstance,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData;\r
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi;\r
+ UINTN NumberRecoveryCapsules;\r
+\r
+ Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {\r
+ CapsuleInstance = CapsuleInstance + 1;\r
+ }\r
+\r
+ if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ PrivateData = PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This);\r
+ BlockIoPpi = PrivateData->CapsuleData[CapsuleInstance - 1].BlockIo;\r
+\r
+ Status = BlockIoPpi->ReadBlocks (\r
+ PrivateData->PeiServices,\r
+ BlockIoPpi,\r
+ PrivateData->CapsuleData[CapsuleInstance - 1].IndexBlock,\r
+ PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleStartLBA,\r
+ PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleSize,\r
+ Buffer\r
+ );\r
+ return Status;\r
+}\r
+\r
+/**\r
+ This function compares two ASCII strings in case sensitive/insensitive way.\r
+\r
+ @param Source1 The first string.\r
+ @param Source2 The second string.\r
+ @param Size The maximum comparison length.\r
+ @param CaseSensitive Flag to indicate whether the comparison is case sensitive.\r
+\r
+ @retval TRUE The two strings are the same.\r
+ @retval FALSE The two string are not the same.\r
+\r
+**/\r
+BOOLEAN\r
+StringCmp (\r
+ IN UINT8 *Source1,\r
+ IN UINT8 *Source2,\r
+ IN UINTN Size,\r
+ IN BOOLEAN CaseSensitive\r
+ )\r
+{\r
+ UINTN Index;\r
+ UINT8 Dif;\r
+\r
+ for (Index = 0; Index < Size; Index++) {\r
+ if (Source1[Index] == Source2[Index]) {\r
+ continue;\r
+ }\r
+\r
+ if (!CaseSensitive) {\r
+ Dif = (UINT8) ((Source1[Index] > Source2[Index]) ? (Source1[Index] - Source2[Index]) : (Source2[Index] - Source1[Index]));\r
+ if (Dif == ('a' - 'A')) {\r
+ continue;\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
--- /dev/null
+/** @file\r
+ Header file for CD recovery PEIM\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _PEI_CD_EXPRESS_H_\r
+#define _PEI_CD_EXPRESS_H_\r
+\r
+\r
+#include <PiPei.h>\r
+\r
+#include <Ppi/BlockIo.h>\r
+#include <Guid/RecoveryDevice.h>\r
+#include <Ppi/DeviceRecoveryModule.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/PeimEntryPoint.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/PeiServicesTablePointerLib.h>\r
+#include <Library/PeiServicesLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+\r
+\r
+#pragma pack(1)\r
+\r
+#define PEI_CD_EXPRESS_MAX_BLOCK_IO_PPI 8\r
+#define PEI_CD_EXPRESS_MAX_CAPSULE_NUMBER 16\r
+\r
+#define PEI_CD_BLOCK_SIZE 0x800\r
+#define PEI_MEMMORY_PAGE_SIZE 0x1000\r
+\r
+//\r
+// Recovery file name (in root directory)\r
+//\r
+#define PEI_RECOVERY_FILE_NAME "FVMAIN.FV"\r
+\r
+//\r
+// Following are defined according to ISO-9660 specification\r
+//\r
+#define PEI_CD_STANDARD_ID "CD001"\r
+#define PEI_CD_EXPRESS_STANDARD_ID_SIZE 5\r
+\r
+#define PEI_CD_EXPRESS_VOLUME_TYPE_OFFSET 0\r
+#define PEI_CD_EXPRESS_STANDARD_ID_OFFSET 1\r
+#define PEI_CD_EXPRESS_VOLUME_SPACE_OFFSET 80\r
+#define PEI_CD_EXPRESS_ROOT_DIR_RECORD_OFFSET 156\r
+\r
+#define PEI_CD_EXPRESS_VOLUME_TYPE_PRIMARY 1\r
+#define PEI_CD_EXPRESS_VOLUME_TYPE_TERMINATOR 255\r
+\r
+#define PEI_CD_EXPRESS_DIR_FILE_REC_FLAG_ISDIR 0x02\r
+\r
+typedef struct {\r
+ UINTN CapsuleStartLBA;\r
+ UINTN CapsuleSize;\r
+ UINTN IndexBlock;\r
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIo;\r
+} PEI_CD_EXPRESS_CAPSULE_DATA;\r
+\r
+#define PEI_CD_EXPRESS_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('p', 'c', 'd', 'e')\r
+\r
+typedef struct {\r
+\r
+ UINTN Signature;\r
+ EFI_PEI_SERVICES **PeiServices;\r
+ EFI_PEI_DEVICE_RECOVERY_MODULE_PPI DeviceRecoveryPpi;\r
+ EFI_PEI_PPI_DESCRIPTOR PpiDescriptor;\r
+ EFI_PEI_NOTIFY_DESCRIPTOR NotifyDescriptor;\r
+\r
+ UINT8 *BlockBuffer;\r
+ UINTN CapsuleCount;\r
+ PEI_CD_EXPRESS_CAPSULE_DATA CapsuleData[PEI_CD_EXPRESS_MAX_CAPSULE_NUMBER];\r
+\r
+} PEI_CD_EXPRESS_PRIVATE_DATA;\r
+\r
+#define PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS(a) \\r
+ CR (a, \\r
+ PEI_CD_EXPRESS_PRIVATE_DATA, \\r
+ DeviceRecoveryPpi, \\r
+ PEI_CD_EXPRESS_PRIVATE_DATA_SIGNATURE \\r
+ )\r
+\r
+typedef struct {\r
+ UINT8 Length;\r
+ UINT8 ExtendedAttributeRecordLength;\r
+ UINT32 LocationOfExtent[2];\r
+ UINT32 DataLength[2];\r
+ UINT8 DateTime[7];\r
+ UINT8 Flag;\r
+ UINT8 FileUnitSize;\r
+ UINT8 InterleaveGapSize;\r
+ UINT32 VolumeSequenceNumber;\r
+ UINT8 FileIDLength;\r
+ UINT8 FileID[1];\r
+} PEI_CD_EXPRESS_DIR_FILE_RECORD;\r
+\r
+/**\r
+ BlockIo installation notification function. \r
+ \r
+ This function finds out all the current Block IO PPIs in the system and add them\r
+ into private data.\r
+\r
+ @param PeiServices Indirect reference to the PEI Services Table.\r
+ @param NotifyDescriptor Address of the notification descriptor data structure.\r
+ @param Ppi Address of the PPI that was installed.\r
+\r
+ @retval EFI_SUCCESS The function completes successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BlockIoNotifyEntry (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
+ IN VOID *Ppi\r
+ );\r
+\r
+/**\r
+ Finds out all the current Block IO PPIs in the system and add them into private data.\r
+\r
+ @param PrivateData The private data structure that contains recovery module information.\r
+\r
+ @retval EFI_SUCCESS The blocks and volumes are updated successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+UpdateBlocksAndVolumes (\r
+ IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData\r
+ );\r
+\r
+/**\r
+ Returns the number of DXE capsules residing on the device.\r
+\r
+ This function searches for DXE capsules from the associated device and returns\r
+ the number and maximum size in bytes of the capsules discovered. Entry 1 is \r
+ assumed to be the highest load priority and entry N is assumed to be the lowest \r
+ priority.\r
+\r
+ @param[in] PeiServices General-purpose services that are available \r
+ to every PEIM\r
+ @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI\r
+ instance.\r
+ @param[out] NumberRecoveryCapsules Pointer to a caller-allocated UINTN. On \r
+ output, *NumberRecoveryCapsules contains \r
+ the number of recovery capsule images \r
+ available for retrieval from this PEIM \r
+ instance.\r
+\r
+ @retval EFI_SUCCESS One or more capsules were discovered.\r
+ @retval EFI_DEVICE_ERROR A device error occurred.\r
+ @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetNumberRecoveryCapsules (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,\r
+ OUT UINTN *NumberRecoveryCapsules\r
+ );\r
+\r
+/**\r
+ Returns the size and type of the requested recovery capsule.\r
+\r
+ This function gets the size and type of the capsule specified by CapsuleInstance.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to every PEIM\r
+ @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI \r
+ instance.\r
+ @param[in] CapsuleInstance Specifies for which capsule instance to retrieve \r
+ the information. This parameter must be between \r
+ one and the value returned by GetNumberRecoveryCapsules() \r
+ in NumberRecoveryCapsules.\r
+ @param[out] Size A pointer to a caller-allocated UINTN in which \r
+ the size of the requested recovery module is \r
+ returned.\r
+ @param[out] CapsuleType A pointer to a caller-allocated EFI_GUID in which \r
+ the type of the requested recovery capsule is \r
+ returned. The semantic meaning of the value \r
+ returned is defined by the implementation.\r
+\r
+ @retval EFI_SUCCESS One or more capsules were discovered.\r
+ @retval EFI_DEVICE_ERROR A device error occurred.\r
+ @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetRecoveryCapsuleInfo (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,\r
+ IN UINTN CapsuleInstance,\r
+ OUT UINTN *Size,\r
+ OUT EFI_GUID *CapsuleType\r
+ );\r
+\r
+/**\r
+ Loads a DXE capsule from some media into memory.\r
+\r
+ This function, by whatever mechanism, retrieves a DXE capsule from some device\r
+ and loads it into memory. Note that the published interface is device neutral.\r
+\r
+ @param[in] PeiServices General-purpose services that are available \r
+ to every PEIM\r
+ @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI\r
+ instance.\r
+ @param[in] CapsuleInstance Specifies which capsule instance to retrieve.\r
+ @param[out] Buffer Specifies a caller-allocated buffer in which \r
+ the requested recovery capsule will be returned.\r
+\r
+ @retval EFI_SUCCESS The capsule was loaded correctly.\r
+ @retval EFI_DEVICE_ERROR A device error occurred.\r
+ @retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LoadRecoveryCapsule (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,\r
+ IN UINTN CapsuleInstance,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+/**\r
+ Finds out the recovery capsule in the current volume.\r
+\r
+ @param PrivateData The private data structure that contains recovery module information.\r
+\r
+ @retval EFI_SUCCESS The recovery capsule is successfully found in the volume.\r
+ @retval EFI_NOT_FOUND The recovery capsule is not found in the volume.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FindRecoveryCapsules (\r
+ IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData\r
+ );\r
+\r
+/**\r
+ Retrieves the recovery capsule in root directory of the current volume.\r
+\r
+ @param PrivateData The private data structure that contains recovery module information.\r
+ @param BlockIoPpi The Block IO PPI used to access the volume.\r
+ @param IndexBlockDevice The index of current block device.\r
+ @param Lba The starting logic block address to retrieve capsule.\r
+\r
+ @retval EFI_SUCCESS The recovery capsule is successfully found in the volume.\r
+ @retval EFI_NOT_FOUND The recovery capsule is not found in the volume.\r
+ @retval Others \r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RetrieveCapsuleFileFromRoot (\r
+ IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi,\r
+ IN UINTN IndexBlockDevice,\r
+ IN UINT32 Lba\r
+ );\r
+\r
+\r
+/**\r
+ This function compares two ASCII strings in case sensitive/insensitive way.\r
+\r
+ @param Source1 The first string.\r
+ @param Source2 The second string.\r
+ @param Size The maximum comparison length.\r
+ @param CaseSensitive Flag to indicate whether the comparison is case sensitive.\r
+\r
+ @retval TRUE The two strings are the same.\r
+ @retval FALSE The two string are not the same.\r
+\r
+**/\r
+BOOLEAN\r
+StringCmp (\r
+ IN UINT8 *Source1,\r
+ IN UINT8 *Source2,\r
+ IN UINTN Size,\r
+ IN BOOLEAN CaseSensitive\r
+ );\r
+\r
+#pragma pack()\r
+\r
+#endif\r