diff --git a/MdeModulePkg/Include/Guid/RecoveryDevice.h b/MdeModulePkg/Include/Guid/RecoveryDevice.h new file mode 100644 index 0000000000..ad25065c6f --- /dev/null +++ b/MdeModulePkg/Include/Guid/RecoveryDevice.h @@ -0,0 +1,60 @@ +/** @file + Defines Name GUIDs to represent a Recovery Capsule loaded from a recovery device. + + These are contracts between the recovery module and device recovery module + that convey the name of a given recovery module type. + +Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+ +This program and the accompanying materials +are licensed and made available under the terms and conditions +of the BSD License which accompanies this distribution. The +full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _RECOVERY_DEVICE_H_ +#define _RECOVERY_DEVICE_H_ + +/// +/// The Global ID used to identify a recovery capsule that was loaded from a CD/DVD device. +/// +#define RECOVERY_ON_DATA_CD_GUID \ + { \ + 0x5cac0099, 0x0dc9, 0x48e5, {0x80, 0x68, 0xbb, 0x95, 0xf5, 0x40, 0x0a, 0x9f } \ + }; + +/// +/// The Global ID used to identify a recovery capsule that was loaded from floppy device. +/// +#define RECOVERY_ON_FAT_FLOPPY_DISK_GUID \ + { \ + 0x2e3d2e75, 0x9b2e, 0x412d, {0xb4, 0xb1, 0x70, 0x41, 0x6b, 0x87, 0x0, 0xff } \ + }; + +/// +/// The Global ID used to identify a recovery capsule that was loaded from IDE hard drive. +/// +#define RECOVERY_ON_FAT_IDE_DISK_GUID \ + { \ + 0xb38573b6, 0x6200, 0x4ac5, {0xb5, 0x1d, 0x82, 0xe6, 0x59, 0x38, 0xd7, 0x83 } \ + }; + +/// +/// The Global ID used to identify a recovery capsule that was loaded from USB BOT device. +/// +#define RECOVERY_ON_FAT_USB_DISK_GUID \ + { \ + 0x0ffbce19, 0x324c, 0x4690, {0xa0, 0x09, 0x98, 0xc6, 0xae, 0x2e, 0xb1, 0x86 } \ + }; + +extern EFI_GUID gRecoveryOnDataCdGuid; +extern EFI_GUID gRecoveryOnFatFloppyDiskGuid; +extern EFI_GUID gRecoveryOnFatIdeDiskGuid; +extern EFI_GUID gRecoveryOnFatUsbDiskGuid; + +#endif diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index 0efd29a29a..92e56ded55 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -173,6 +173,18 @@ # Include/Guid/EventIdle.h gIdleLoopEventGuid = { 0x3c8d294c, 0x5fc3, 0x4451, { 0xbb, 0x31, 0xc4, 0xc0, 0x32, 0x29, 0x5e, 0x6c } } + ## Include/Guid/RecoveryDevice.h + gRecoveryOnFatUsbDiskGuid = { 0x0FFBCE19, 0x324C, 0x4690, { 0xA0, 0x09, 0x98, 0xC6, 0xAE, 0x2E, 0xB1, 0x86 }} + + ## Include/Guid/RecoveryDevice.h + gRecoveryOnFatIdeDiskGuid = { 0xB38573B6, 0x6200, 0x4AC5, { 0xB5, 0x1D, 0x82, 0xE6, 0x59, 0x38, 0xD7, 0x83 }} + + ## Include/Guid/RecoveryDevice.h + gRecoveryOnFatFloppyDiskGuid = { 0x2E3D2E75, 0x9B2E, 0x412D, { 0xB4, 0xB1, 0x70, 0x41, 0x6B, 0x87, 0x00, 0xFF }} + + ## Include/Guid/RecoveryDevice.h + gRecoveryOnDataCdGuid = { 0x5CAC0099, 0x0DC9, 0x48E5, { 0x80, 0x68, 0xBB, 0x95, 0xF5, 0x40, 0x0A, 0x9F }} + [Ppis] ## Include/Ppi/AtaController.h gPeiAtaControllerPpiGuid = { 0xa45e60d1, 0xc719, 0x44aa, { 0xb0, 0x7a, 0xaa, 0x77, 0x7f, 0x85, 0x90, 0x6d }} diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc index 1e8cd5419e..171a8d0323 100644 --- a/MdeModulePkg/MdeModulePkg.dsc +++ b/MdeModulePkg/MdeModulePkg.dsc @@ -245,6 +245,7 @@ MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf + MdeModulePkg/Universal/Disk/CdExpressPei/CdExpressPei.inf MdeModulePkg/Universal/DriverSampleDxe/DriverSampleDxe.inf MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf MdeModulePkg/Universal/MemoryTest/GenericMemoryTestDxe/GenericMemoryTestDxe.inf diff --git a/MdeModulePkg/Universal/Disk/CdExpressPei/CdExpressPei.inf b/MdeModulePkg/Universal/Disk/CdExpressPei/CdExpressPei.inf new file mode 100644 index 0000000000..287f1ff4a9 --- /dev/null +++ b/MdeModulePkg/Universal/Disk/CdExpressPei/CdExpressPei.inf @@ -0,0 +1,69 @@ +## @file +# Component description file for PeiCdExpress module. +# +# This module reads data from CDROM device by all installed block IO ppi and +# finds whether there is Recovery data in the device. If it finds recovery +# data, it will install Device Recovery Module PPI. +# +# Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions +# of the BSD License which accompanies this distribution. The +# full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = CdExpressPei + FILE_GUID = 31e147a6-d39a-4147-9da3-befd4d523243 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + + ENTRY_POINT = CdExpressPeimEntry + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + PeiCdExpress.c + PeiCdExpress.h + + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + BaseMemoryLib + PeimEntryPoint + DebugLib + PeiServicesTablePointerLib + PeiServicesLib + MemoryAllocationLib + PcdLib + +[Guids] + gRecoveryOnDataCdGuid # ALWAYS_CONSUMED + + +[Ppis] + gEfiPeiVirtualBlockIoPpiGuid # PPI_NOTIFY SOMETIMES_CONSUMED + gEfiPeiDeviceRecoveryModulePpiGuid # PPI ALWAYS_PRODUCED + +[FeaturePcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdFrameworkCompatibilitySupport ## CONSUMES + +[Depex] + gEfiPeiMemoryDiscoveredPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid + + + diff --git a/MdeModulePkg/Universal/Disk/CdExpressPei/PeiCdExpress.c b/MdeModulePkg/Universal/Disk/CdExpressPei/PeiCdExpress.c new file mode 100644 index 0000000000..ee0b4e6869 --- /dev/null +++ b/MdeModulePkg/Universal/Disk/CdExpressPei/PeiCdExpress.c @@ -0,0 +1,618 @@ +/** @file + Source file for CD recovery PEIM + +Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+ +This program and the accompanying materials +are licensed and made available under the terms and conditions +of the BSD License which accompanies this distribution. The +full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "PeiCdExpress.h" + +PEI_CD_EXPRESS_PRIVATE_DATA *mPrivateData = NULL; + +/** + Installs the Device Recovery Module PPI, Initialize BlockIo Ppi + installation notification + + @param FileHandle The file handle of the image. + @param PeiServices General purpose services available to every PEIM. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_OUT_OF_RESOURCES There is not enough system memory. + +**/ +EFI_STATUS +EFIAPI +CdExpressPeimEntry ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData; + + if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) { + return EFI_SUCCESS; + } + + PrivateData = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (*PrivateData))); + if (PrivateData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Initialize Private Data (to zero, as is required by subsequent operations) + // + ZeroMem (PrivateData, sizeof (*PrivateData)); + PrivateData->Signature = PEI_CD_EXPRESS_PRIVATE_DATA_SIGNATURE; + + PrivateData->BlockBuffer = AllocatePages (EFI_SIZE_TO_PAGES (PEI_CD_BLOCK_SIZE)); + if (PrivateData->BlockBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + PrivateData->CapsuleCount = 0; + Status = UpdateBlocksAndVolumes (PrivateData); + + // + // Installs Ppi + // + PrivateData->DeviceRecoveryPpi.GetNumberRecoveryCapsules = GetNumberRecoveryCapsules; + PrivateData->DeviceRecoveryPpi.GetRecoveryCapsuleInfo = GetRecoveryCapsuleInfo; + PrivateData->DeviceRecoveryPpi.LoadRecoveryCapsule = LoadRecoveryCapsule; + + PrivateData->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST); + PrivateData->PpiDescriptor.Guid = &gEfiPeiDeviceRecoveryModulePpiGuid; + PrivateData->PpiDescriptor.Ppi = &PrivateData->DeviceRecoveryPpi; + + Status = PeiServicesInstallPpi (&PrivateData->PpiDescriptor); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + // + // PrivateData is allocated now, set it to the module variable + // + mPrivateData = PrivateData; + + // + // Installs Block Io Ppi notification function + // + PrivateData->NotifyDescriptor.Flags = + ( + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | + EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST + ); + PrivateData->NotifyDescriptor.Guid = &gEfiPeiVirtualBlockIoPpiGuid; + PrivateData->NotifyDescriptor.Notify = BlockIoNotifyEntry; + return PeiServicesNotifyPpi (&PrivateData->NotifyDescriptor); + +} + +/** + BlockIo installation notification function. + + This function finds out all the current Block IO PPIs in the system and add them + into private data. + + @param PeiServices Indirect reference to the PEI Services Table. + @param NotifyDescriptor Address of the notification descriptor data structure. + @param Ppi Address of the PPI that was installed. + + @retval EFI_SUCCESS The function completes successfully. + +**/ +EFI_STATUS +EFIAPI +BlockIoNotifyEntry ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ) +{ + UpdateBlocksAndVolumes (mPrivateData); + + return EFI_SUCCESS; +} + +/** + Finds out all the current Block IO PPIs in the system and add them into private data. + + @param PrivateData The private data structure that contains recovery module information. + + @retval EFI_SUCCESS The blocks and volumes are updated successfully. + +**/ +EFI_STATUS +UpdateBlocksAndVolumes ( + IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData + ) +{ + EFI_STATUS Status; + EFI_PEI_PPI_DESCRIPTOR *TempPpiDescriptor; + UINTN BlockIoPpiInstance; + EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi; + UINTN NumberBlockDevices; + UINTN IndexBlockDevice; + EFI_PEI_BLOCK_IO_MEDIA Media; + EFI_PEI_SERVICES **PeiServices; + + IndexBlockDevice = 0; + // + // Find out all Block Io Ppi instances within the system + // Assuming all device Block Io Peims are dispatched already + // + for (BlockIoPpiInstance = 0; BlockIoPpiInstance < PEI_CD_EXPRESS_MAX_BLOCK_IO_PPI; BlockIoPpiInstance++) { + Status = PeiServicesLocatePpi ( + &gEfiPeiVirtualBlockIoPpiGuid, + BlockIoPpiInstance, + &TempPpiDescriptor, + (VOID **) &BlockIoPpi + ); + if (EFI_ERROR (Status)) { + // + // Done with all Block Io Ppis + // + break; + } + + PeiServices = (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (); + Status = BlockIoPpi->GetNumberOfBlockDevices ( + PeiServices, + BlockIoPpi, + &NumberBlockDevices + ); + if (EFI_ERROR (Status) || (NumberBlockDevices == 0)) { + continue; + } + // + // Just retrieve the first block, should emulate all blocks. + // + for (IndexBlockDevice = 1; IndexBlockDevice <= NumberBlockDevices && PrivateData->CapsuleCount < PEI_CD_EXPRESS_MAX_CAPSULE_NUMBER; IndexBlockDevice ++) { + Status = BlockIoPpi->GetBlockDeviceMediaInfo ( + PeiServices, + BlockIoPpi, + IndexBlockDevice, + &Media + ); + if (EFI_ERROR (Status) || + !Media.MediaPresent || + ((Media.DeviceType != IdeCDROM) && (Media.DeviceType != UsbMassStorage)) || + (Media.BlockSize != PEI_CD_BLOCK_SIZE) + ) { + continue; + } + + DEBUG ((EFI_D_INFO, "PeiCdExpress DeviceType is %d\n", Media.DeviceType)); + DEBUG ((EFI_D_INFO, "PeiCdExpress MediaPresent is %d\n", Media.MediaPresent)); + DEBUG ((EFI_D_INFO, "PeiCdExpress BlockSize is 0x%x\n", Media.BlockSize)); + DEBUG ((EFI_D_INFO, "PeiCdExpress Status is %d\n", Status)); + + DEBUG ((EFI_D_INFO, "IndexBlockDevice is %d\n", IndexBlockDevice)); + PrivateData->CapsuleData[PrivateData->CapsuleCount].IndexBlock = IndexBlockDevice; + PrivateData->CapsuleData[PrivateData->CapsuleCount].BlockIo = BlockIoPpi; + Status = FindRecoveryCapsules (PrivateData); + DEBUG ((EFI_D_INFO, "Status is %d\n", Status)); + + if (EFI_ERROR (Status)) { + continue; + } + + PrivateData->CapsuleCount++; + } + + } + + return EFI_SUCCESS; +} + +/** + Finds out the recovery capsule in the current volume. + + @param PrivateData The private data structure that contains recovery module information. + + @retval EFI_SUCCESS The recovery capsule is successfully found in the volume. + @retval EFI_NOT_FOUND The recovery capsule is not found in the volume. + +**/ +EFI_STATUS +EFIAPI +FindRecoveryCapsules ( + IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData + ) +{ + EFI_STATUS Status; + UINTN Lba; + EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi; + UINTN BufferSize; + UINT8 *Buffer; + UINT8 Type; + UINT8 *StandardID; + UINT32 RootDirLBA; + PEI_CD_EXPRESS_DIR_FILE_RECORD *RoorDirRecord; + UINTN VolumeSpaceSize; + BOOLEAN StartOfVolume; + UINTN OriginalLBA; + UINTN IndexBlockDevice; + + Buffer = PrivateData->BlockBuffer; + BufferSize = PEI_CD_BLOCK_SIZE; + + Lba = 16; + // + // The volume descriptor starts on Lba 16 + // + IndexBlockDevice = PrivateData->CapsuleData[PrivateData->CapsuleCount].IndexBlock; + BlockIoPpi = PrivateData->CapsuleData[PrivateData->CapsuleCount].BlockIo; + + VolumeSpaceSize = 0; + StartOfVolume = TRUE; + OriginalLBA = 16; + + while (TRUE) { + SetMem (Buffer, BufferSize, 0); + Status = BlockIoPpi->ReadBlocks ( + PrivateData->PeiServices, + BlockIoPpi, + IndexBlockDevice, + Lba, + BufferSize, + Buffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + StandardID = (UINT8 *) (Buffer + PEI_CD_EXPRESS_STANDARD_ID_OFFSET); + if (!StringCmp (StandardID, (UINT8 *) PEI_CD_STANDARD_ID, PEI_CD_EXPRESS_STANDARD_ID_SIZE, TRUE)) { + break; + } + + if (StartOfVolume) { + OriginalLBA = Lba; + StartOfVolume = FALSE; + } + + Type = *(UINT8 *) (Buffer + PEI_CD_EXPRESS_VOLUME_TYPE_OFFSET); + if (Type == PEI_CD_EXPRESS_VOLUME_TYPE_TERMINATOR) { + if (VolumeSpaceSize == 0) { + break; + } else { + Lba = (OriginalLBA + VolumeSpaceSize); + VolumeSpaceSize = 0; + StartOfVolume = TRUE; + continue; + } + } + + if (Type != PEI_CD_EXPRESS_VOLUME_TYPE_PRIMARY) { + Lba++; + continue; + } + + VolumeSpaceSize = *(UINT32 *) (Buffer + PEI_CD_EXPRESS_VOLUME_SPACE_OFFSET); + + RoorDirRecord = (PEI_CD_EXPRESS_DIR_FILE_RECORD *) (Buffer + PEI_CD_EXPRESS_ROOT_DIR_RECORD_OFFSET); + RootDirLBA = RoorDirRecord->LocationOfExtent[0]; + + Status = RetrieveCapsuleFileFromRoot (PrivateData, BlockIoPpi, IndexBlockDevice, RootDirLBA); + if (!EFI_ERROR (Status)) { + // + // Just look for the first primary descriptor + // + return EFI_SUCCESS; + } + + Lba++; + } + + return EFI_NOT_FOUND; +} + +/** + Retrieves the recovery capsule in root directory of the current volume. + + @param PrivateData The private data structure that contains recovery module information. + @param BlockIoPpi The Block IO PPI used to access the volume. + @param IndexBlockDevice The index of current block device. + @param Lba The starting logic block address to retrieve capsule. + + @retval EFI_SUCCESS The recovery capsule is successfully found in the volume. + @retval EFI_NOT_FOUND The recovery capsule is not found in the volume. + @retval Others + +**/ +EFI_STATUS +EFIAPI +RetrieveCapsuleFileFromRoot ( + IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData, + IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi, + IN UINTN IndexBlockDevice, + IN UINT32 Lba + ) +{ + EFI_STATUS Status; + UINTN BufferSize; + UINT8 *Buffer; + PEI_CD_EXPRESS_DIR_FILE_RECORD *FileRecord; + UINTN Index; + + Buffer = PrivateData->BlockBuffer; + BufferSize = PEI_CD_BLOCK_SIZE; + + SetMem (Buffer, BufferSize, 0); + + Status = BlockIoPpi->ReadBlocks ( + PrivateData->PeiServices, + BlockIoPpi, + IndexBlockDevice, + Lba, + BufferSize, + Buffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + while (1) { + FileRecord = (PEI_CD_EXPRESS_DIR_FILE_RECORD *) Buffer; + + if (FileRecord->Length == 0) { + break; + } + // + // Not intend to check other flag now + // + if ((FileRecord->Flag & PEI_CD_EXPRESS_DIR_FILE_REC_FLAG_ISDIR) != 0) { + Buffer += FileRecord->Length; + continue; + } + + for (Index = 0; Index < FileRecord->FileIDLength; Index++) { + if (FileRecord->FileID[Index] == ';') { + break; + } + } + + if (Index != (sizeof (PEI_RECOVERY_FILE_NAME) - 1)) { + Buffer += FileRecord->Length; + continue; + } + + if (!StringCmp (FileRecord->FileID, (UINT8 *) PEI_RECOVERY_FILE_NAME, sizeof (PEI_RECOVERY_FILE_NAME) - 1, FALSE)) { + Buffer += FileRecord->Length; + continue; + } + + PrivateData->CapsuleData[PrivateData->CapsuleCount].CapsuleStartLBA = FileRecord->LocationOfExtent[0]; + PrivateData->CapsuleData[PrivateData->CapsuleCount].CapsuleSize = + ( + FileRecord->DataLength[0] / + PEI_CD_BLOCK_SIZE + + 1 + ) * + PEI_CD_BLOCK_SIZE; + + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; +} + +/** + Returns the number of DXE capsules residing on the device. + + This function searches for DXE capsules from the associated device and returns + the number and maximum size in bytes of the capsules discovered. Entry 1 is + assumed to be the highest load priority and entry N is assumed to be the lowest + priority. + + @param[in] PeiServices General-purpose services that are available + to every PEIM + @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI + instance. + @param[out] NumberRecoveryCapsules Pointer to a caller-allocated UINTN. On + output, *NumberRecoveryCapsules contains + the number of recovery capsule images + available for retrieval from this PEIM + instance. + + @retval EFI_SUCCESS One or more capsules were discovered. + @retval EFI_DEVICE_ERROR A device error occurred. + @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found. + +**/ +EFI_STATUS +EFIAPI +GetNumberRecoveryCapsules ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This, + OUT UINTN *NumberRecoveryCapsules + ) +{ + PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData; + + PrivateData = PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This); + UpdateBlocksAndVolumes (PrivateData); + *NumberRecoveryCapsules = PrivateData->CapsuleCount; + + if (*NumberRecoveryCapsules == 0) { + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + +/** + Returns the size and type of the requested recovery capsule. + + This function gets the size and type of the capsule specified by CapsuleInstance. + + @param[in] PeiServices General-purpose services that are available to every PEIM + @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI + instance. + @param[in] CapsuleInstance Specifies for which capsule instance to retrieve + the information. This parameter must be between + one and the value returned by GetNumberRecoveryCapsules() + in NumberRecoveryCapsules. + @param[out] Size A pointer to a caller-allocated UINTN in which + the size of the requested recovery module is + returned. + @param[out] CapsuleType A pointer to a caller-allocated EFI_GUID in which + the type of the requested recovery capsule is + returned. The semantic meaning of the value + returned is defined by the implementation. + + @retval EFI_SUCCESS One or more capsules were discovered. + @retval EFI_DEVICE_ERROR A device error occurred. + @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found. + +**/ +EFI_STATUS +EFIAPI +GetRecoveryCapsuleInfo ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This, + IN UINTN CapsuleInstance, + OUT UINTN *Size, + OUT EFI_GUID *CapsuleType + ) +{ + PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData; + UINTN NumberRecoveryCapsules; + EFI_STATUS Status; + + Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules); + + if (EFI_ERROR (Status)) { + return Status; + } + + if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) { + CapsuleInstance = CapsuleInstance + 1; + } + + if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) { + return EFI_NOT_FOUND; + } + + PrivateData = PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This); + + *Size = PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleSize; + CopyMem ( + CapsuleType, + &gRecoveryOnDataCdGuid, + sizeof (EFI_GUID) + ); + + return EFI_SUCCESS; +} + +/** + Loads a DXE capsule from some media into memory. + + This function, by whatever mechanism, retrieves a DXE capsule from some device + and loads it into memory. Note that the published interface is device neutral. + + @param[in] PeiServices General-purpose services that are available + to every PEIM + @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI + instance. + @param[in] CapsuleInstance Specifies which capsule instance to retrieve. + @param[out] Buffer Specifies a caller-allocated buffer in which + the requested recovery capsule will be returned. + + @retval EFI_SUCCESS The capsule was loaded correctly. + @retval EFI_DEVICE_ERROR A device error occurred. + @retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found. + +**/ +EFI_STATUS +EFIAPI +LoadRecoveryCapsule ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This, + IN UINTN CapsuleInstance, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData; + EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi; + UINTN NumberRecoveryCapsules; + + Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules); + + if (EFI_ERROR (Status)) { + return Status; + } + + if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) { + CapsuleInstance = CapsuleInstance + 1; + } + + if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) { + return EFI_NOT_FOUND; + } + + PrivateData = PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This); + BlockIoPpi = PrivateData->CapsuleData[CapsuleInstance - 1].BlockIo; + + Status = BlockIoPpi->ReadBlocks ( + PrivateData->PeiServices, + BlockIoPpi, + PrivateData->CapsuleData[CapsuleInstance - 1].IndexBlock, + PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleStartLBA, + PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleSize, + Buffer + ); + return Status; +} + +/** + This function compares two ASCII strings in case sensitive/insensitive way. + + @param Source1 The first string. + @param Source2 The second string. + @param Size The maximum comparison length. + @param CaseSensitive Flag to indicate whether the comparison is case sensitive. + + @retval TRUE The two strings are the same. + @retval FALSE The two string are not the same. + +**/ +BOOLEAN +StringCmp ( + IN UINT8 *Source1, + IN UINT8 *Source2, + IN UINTN Size, + IN BOOLEAN CaseSensitive + ) +{ + UINTN Index; + UINT8 Dif; + + for (Index = 0; Index < Size; Index++) { + if (Source1[Index] == Source2[Index]) { + continue; + } + + if (!CaseSensitive) { + Dif = (UINT8) ((Source1[Index] > Source2[Index]) ? (Source1[Index] - Source2[Index]) : (Source2[Index] - Source1[Index])); + if (Dif == ('a' - 'A')) { + continue; + } + } + + return FALSE; + } + + return TRUE; +} diff --git a/MdeModulePkg/Universal/Disk/CdExpressPei/PeiCdExpress.h b/MdeModulePkg/Universal/Disk/CdExpressPei/PeiCdExpress.h new file mode 100644 index 0000000000..99edd3d5a2 --- /dev/null +++ b/MdeModulePkg/Universal/Disk/CdExpressPei/PeiCdExpress.h @@ -0,0 +1,297 @@ +/** @file + Header file for CD recovery PEIM + +Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+ +This program and the accompanying materials +are licensed and made available under the terms and conditions +of the BSD License which accompanies this distribution. The +full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _PEI_CD_EXPRESS_H_ +#define _PEI_CD_EXPRESS_H_ + + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +#pragma pack(1) + +#define PEI_CD_EXPRESS_MAX_BLOCK_IO_PPI 8 +#define PEI_CD_EXPRESS_MAX_CAPSULE_NUMBER 16 + +#define PEI_CD_BLOCK_SIZE 0x800 +#define PEI_MEMMORY_PAGE_SIZE 0x1000 + +// +// Recovery file name (in root directory) +// +#define PEI_RECOVERY_FILE_NAME "FVMAIN.FV" + +// +// Following are defined according to ISO-9660 specification +// +#define PEI_CD_STANDARD_ID "CD001" +#define PEI_CD_EXPRESS_STANDARD_ID_SIZE 5 + +#define PEI_CD_EXPRESS_VOLUME_TYPE_OFFSET 0 +#define PEI_CD_EXPRESS_STANDARD_ID_OFFSET 1 +#define PEI_CD_EXPRESS_VOLUME_SPACE_OFFSET 80 +#define PEI_CD_EXPRESS_ROOT_DIR_RECORD_OFFSET 156 + +#define PEI_CD_EXPRESS_VOLUME_TYPE_PRIMARY 1 +#define PEI_CD_EXPRESS_VOLUME_TYPE_TERMINATOR 255 + +#define PEI_CD_EXPRESS_DIR_FILE_REC_FLAG_ISDIR 0x02 + +typedef struct { + UINTN CapsuleStartLBA; + UINTN CapsuleSize; + UINTN IndexBlock; + EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIo; +} PEI_CD_EXPRESS_CAPSULE_DATA; + +#define PEI_CD_EXPRESS_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('p', 'c', 'd', 'e') + +typedef struct { + + UINTN Signature; + EFI_PEI_SERVICES **PeiServices; + EFI_PEI_DEVICE_RECOVERY_MODULE_PPI DeviceRecoveryPpi; + EFI_PEI_PPI_DESCRIPTOR PpiDescriptor; + EFI_PEI_NOTIFY_DESCRIPTOR NotifyDescriptor; + + UINT8 *BlockBuffer; + UINTN CapsuleCount; + PEI_CD_EXPRESS_CAPSULE_DATA CapsuleData[PEI_CD_EXPRESS_MAX_CAPSULE_NUMBER]; + +} PEI_CD_EXPRESS_PRIVATE_DATA; + +#define PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS(a) \ + CR (a, \ + PEI_CD_EXPRESS_PRIVATE_DATA, \ + DeviceRecoveryPpi, \ + PEI_CD_EXPRESS_PRIVATE_DATA_SIGNATURE \ + ) + +typedef struct { + UINT8 Length; + UINT8 ExtendedAttributeRecordLength; + UINT32 LocationOfExtent[2]; + UINT32 DataLength[2]; + UINT8 DateTime[7]; + UINT8 Flag; + UINT8 FileUnitSize; + UINT8 InterleaveGapSize; + UINT32 VolumeSequenceNumber; + UINT8 FileIDLength; + UINT8 FileID[1]; +} PEI_CD_EXPRESS_DIR_FILE_RECORD; + +/** + BlockIo installation notification function. + + This function finds out all the current Block IO PPIs in the system and add them + into private data. + + @param PeiServices Indirect reference to the PEI Services Table. + @param NotifyDescriptor Address of the notification descriptor data structure. + @param Ppi Address of the PPI that was installed. + + @retval EFI_SUCCESS The function completes successfully. + +**/ +EFI_STATUS +EFIAPI +BlockIoNotifyEntry ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ); + +/** + Finds out all the current Block IO PPIs in the system and add them into private data. + + @param PrivateData The private data structure that contains recovery module information. + + @retval EFI_SUCCESS The blocks and volumes are updated successfully. + +**/ +EFI_STATUS +UpdateBlocksAndVolumes ( + IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData + ); + +/** + Returns the number of DXE capsules residing on the device. + + This function searches for DXE capsules from the associated device and returns + the number and maximum size in bytes of the capsules discovered. Entry 1 is + assumed to be the highest load priority and entry N is assumed to be the lowest + priority. + + @param[in] PeiServices General-purpose services that are available + to every PEIM + @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI + instance. + @param[out] NumberRecoveryCapsules Pointer to a caller-allocated UINTN. On + output, *NumberRecoveryCapsules contains + the number of recovery capsule images + available for retrieval from this PEIM + instance. + + @retval EFI_SUCCESS One or more capsules were discovered. + @retval EFI_DEVICE_ERROR A device error occurred. + @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found. + +**/ +EFI_STATUS +EFIAPI +GetNumberRecoveryCapsules ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This, + OUT UINTN *NumberRecoveryCapsules + ); + +/** + Returns the size and type of the requested recovery capsule. + + This function gets the size and type of the capsule specified by CapsuleInstance. + + @param[in] PeiServices General-purpose services that are available to every PEIM + @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI + instance. + @param[in] CapsuleInstance Specifies for which capsule instance to retrieve + the information. This parameter must be between + one and the value returned by GetNumberRecoveryCapsules() + in NumberRecoveryCapsules. + @param[out] Size A pointer to a caller-allocated UINTN in which + the size of the requested recovery module is + returned. + @param[out] CapsuleType A pointer to a caller-allocated EFI_GUID in which + the type of the requested recovery capsule is + returned. The semantic meaning of the value + returned is defined by the implementation. + + @retval EFI_SUCCESS One or more capsules were discovered. + @retval EFI_DEVICE_ERROR A device error occurred. + @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found. + +**/ +EFI_STATUS +EFIAPI +GetRecoveryCapsuleInfo ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This, + IN UINTN CapsuleInstance, + OUT UINTN *Size, + OUT EFI_GUID *CapsuleType + ); + +/** + Loads a DXE capsule from some media into memory. + + This function, by whatever mechanism, retrieves a DXE capsule from some device + and loads it into memory. Note that the published interface is device neutral. + + @param[in] PeiServices General-purpose services that are available + to every PEIM + @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI + instance. + @param[in] CapsuleInstance Specifies which capsule instance to retrieve. + @param[out] Buffer Specifies a caller-allocated buffer in which + the requested recovery capsule will be returned. + + @retval EFI_SUCCESS The capsule was loaded correctly. + @retval EFI_DEVICE_ERROR A device error occurred. + @retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found. + +**/ +EFI_STATUS +EFIAPI +LoadRecoveryCapsule ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This, + IN UINTN CapsuleInstance, + OUT VOID *Buffer + ); + +/** + Finds out the recovery capsule in the current volume. + + @param PrivateData The private data structure that contains recovery module information. + + @retval EFI_SUCCESS The recovery capsule is successfully found in the volume. + @retval EFI_NOT_FOUND The recovery capsule is not found in the volume. + +**/ +EFI_STATUS +EFIAPI +FindRecoveryCapsules ( + IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData + ); + +/** + Retrieves the recovery capsule in root directory of the current volume. + + @param PrivateData The private data structure that contains recovery module information. + @param BlockIoPpi The Block IO PPI used to access the volume. + @param IndexBlockDevice The index of current block device. + @param Lba The starting logic block address to retrieve capsule. + + @retval EFI_SUCCESS The recovery capsule is successfully found in the volume. + @retval EFI_NOT_FOUND The recovery capsule is not found in the volume. + @retval Others + +**/ +EFI_STATUS +EFIAPI +RetrieveCapsuleFileFromRoot ( + IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData, + IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi, + IN UINTN IndexBlockDevice, + IN UINT32 Lba + ); + + +/** + This function compares two ASCII strings in case sensitive/insensitive way. + + @param Source1 The first string. + @param Source2 The second string. + @param Size The maximum comparison length. + @param CaseSensitive Flag to indicate whether the comparison is case sensitive. + + @retval TRUE The two strings are the same. + @retval FALSE The two string are not the same. + +**/ +BOOLEAN +StringCmp ( + IN UINT8 *Source1, + IN UINT8 *Source2, + IN UINTN Size, + IN BOOLEAN CaseSensitive + ); + +#pragma pack() + +#endif