/** 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; EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2Ppi; 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; BlockIo2Ppi = PrivateData->CapsuleData[CapsuleInstance - 1].BlockIo2; if (BlockIo2Ppi != NULL) { Status = BlockIo2Ppi->ReadBlocks ( PeiServices, BlockIo2Ppi, PrivateData->CapsuleData[CapsuleInstance - 1].IndexBlock, PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleStartLBA, PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleSize, Buffer ); } else { Status = BlockIoPpi->ReadBlocks ( PeiServices, BlockIoPpi, PrivateData->CapsuleData[CapsuleInstance - 1].IndexBlock, PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleStartLBA, PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleSize, Buffer ); } return Status; }
/** 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. @param BlockIo2 Boolean to show whether using BlockIo2 or BlockIo. @retval EFI_SUCCESS The blocks and volumes are updated successfully. **/ EFI_STATUS UpdateBlocksAndVolumes ( IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData, IN BOOLEAN BlockIo2 ) { EFI_STATUS Status; EFI_PEI_PPI_DESCRIPTOR *TempPpiDescriptor; UINTN BlockIoPpiInstance; EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi; EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2Ppi; UINTN NumberBlockDevices; UINTN IndexBlockDevice; EFI_PEI_BLOCK_IO_MEDIA Media; EFI_PEI_BLOCK_IO2_MEDIA Media2; EFI_PEI_SERVICES **PeiServices; IndexBlockDevice = 0; BlockIo2Ppi = NULL; BlockIoPpi = NULL; // // 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++) { if (BlockIo2) { Status = PeiServicesLocatePpi ( &gEfiPeiVirtualBlockIo2PpiGuid, BlockIoPpiInstance, &TempPpiDescriptor, (VOID **) &BlockIo2Ppi ); } else { Status = PeiServicesLocatePpi ( &gEfiPeiVirtualBlockIoPpiGuid, BlockIoPpiInstance, &TempPpiDescriptor, (VOID **) &BlockIoPpi ); } if (EFI_ERROR (Status)) { // // Done with all Block Io Ppis // break; } PeiServices = (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (); if (BlockIo2) { Status = BlockIo2Ppi->GetNumberOfBlockDevices ( PeiServices, BlockIo2Ppi, &NumberBlockDevices ); } else { 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 ++) { if (BlockIo2) { Status = BlockIo2Ppi->GetBlockDeviceMediaInfo ( PeiServices, BlockIo2Ppi, IndexBlockDevice, &Media2 ); if (EFI_ERROR (Status) || !Media2.MediaPresent || ((Media2.InterfaceType != MSG_ATAPI_DP) && (Media2.InterfaceType != MSG_USB_DP)) || (Media2.BlockSize != PEI_CD_BLOCK_SIZE) ) { continue; } DEBUG ((EFI_D_INFO, "PeiCdExpress InterfaceType is %d\n", Media2.InterfaceType)); DEBUG ((EFI_D_INFO, "PeiCdExpress MediaPresent is %d\n", Media2.MediaPresent)); DEBUG ((EFI_D_INFO, "PeiCdExpress BlockSize is 0x%x\n", Media2.BlockSize)); } else { 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; if (BlockIo2) { PrivateData->CapsuleData[PrivateData->CapsuleCount].BlockIo2 = BlockIo2Ppi; } else { 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; EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2Ppi; 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; BlockIo2Ppi = PrivateData->CapsuleData[PrivateData->CapsuleCount].BlockIo2; VolumeSpaceSize = 0; StartOfVolume = TRUE; OriginalLBA = 16; while (TRUE) { SetMem (Buffer, BufferSize, 0); if (BlockIo2Ppi != NULL) { Status = BlockIo2Ppi->ReadBlocks ( (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (), BlockIo2Ppi, IndexBlockDevice, Lba, BufferSize, Buffer ); } else { Status = BlockIoPpi->ReadBlocks ( (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (), 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, BlockIo2Ppi, IndexBlockDevice, RootDirLBA); if (!EFI_ERROR (Status)) { // // Just look for the first primary descriptor // return EFI_SUCCESS; } Lba++; } return EFI_NOT_FOUND; }
/** Discover all the block I/O devices to find the FAT volume. @param PrivateData Global memory map for accessing global variables. @param BlockIo2 Boolean to show whether using BlockIo2 or BlockIo @retval EFI_SUCCESS The function completed successfully. **/ EFI_STATUS UpdateBlocksAndVolumes ( IN OUT PEI_FAT_PRIVATE_DATA *PrivateData, IN BOOLEAN BlockIo2 ) { EFI_STATUS Status; EFI_PEI_PPI_DESCRIPTOR *TempPpiDescriptor; UINTN BlockIoPpiInstance; EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi; EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2Ppi; UINTN NumberBlockDevices; UINTN Index; EFI_PEI_BLOCK_IO_MEDIA Media; EFI_PEI_BLOCK_IO2_MEDIA Media2; PEI_FAT_VOLUME Volume; EFI_PEI_SERVICES **PeiServices; PeiServices = (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (); BlockIo2Ppi = NULL; BlockIoPpi = NULL; // // Clean up caches // for (Index = 0; Index < PEI_FAT_CACHE_SIZE; Index++) { PrivateData->CacheBuffer[Index].Valid = FALSE; } PrivateData->BlockDeviceCount = 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_FAT_MAX_BLOCK_IO_PPI; BlockIoPpiInstance++) { if (BlockIo2) { Status = PeiServicesLocatePpi ( &gEfiPeiVirtualBlockIo2PpiGuid, BlockIoPpiInstance, &TempPpiDescriptor, (VOID **) &BlockIo2Ppi ); } else { Status = PeiServicesLocatePpi ( &gEfiPeiVirtualBlockIoPpiGuid, BlockIoPpiInstance, &TempPpiDescriptor, (VOID **) &BlockIoPpi ); } if (EFI_ERROR (Status)) { // // Done with all Block Io Ppis // break; } if (BlockIo2) { Status = BlockIo2Ppi->GetNumberOfBlockDevices ( PeiServices, BlockIo2Ppi, &NumberBlockDevices ); } else { Status = BlockIoPpi->GetNumberOfBlockDevices ( PeiServices, BlockIoPpi, &NumberBlockDevices ); } if (EFI_ERROR (Status)) { continue; } for (Index = 1; Index <= NumberBlockDevices && PrivateData->BlockDeviceCount < PEI_FAT_MAX_BLOCK_DEVICE; Index++) { if (BlockIo2) { Status = BlockIo2Ppi->GetBlockDeviceMediaInfo ( PeiServices, BlockIo2Ppi, Index, &Media2 ); if (EFI_ERROR (Status) || !Media2.MediaPresent) { continue; } PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockIo2 = BlockIo2Ppi; PrivateData->BlockDevice[PrivateData->BlockDeviceCount].InterfaceType = Media2.InterfaceType; PrivateData->BlockDevice[PrivateData->BlockDeviceCount].LastBlock = Media2.LastBlock; PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockSize = Media2.BlockSize; } else { Status = BlockIoPpi->GetBlockDeviceMediaInfo ( PeiServices, BlockIoPpi, Index, &Media ); if (EFI_ERROR (Status) || !Media.MediaPresent) { continue; } PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockIo = BlockIoPpi; PrivateData->BlockDevice[PrivateData->BlockDeviceCount].DevType = Media.DeviceType; PrivateData->BlockDevice[PrivateData->BlockDeviceCount].LastBlock = Media.LastBlock; PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockSize = (UINT32) Media.BlockSize; } PrivateData->BlockDevice[PrivateData->BlockDeviceCount].IoAlign = 0; // // Not used here // PrivateData->BlockDevice[PrivateData->BlockDeviceCount].Logical = FALSE; PrivateData->BlockDevice[PrivateData->BlockDeviceCount].PartitionChecked = FALSE; PrivateData->BlockDevice[PrivateData->BlockDeviceCount].PhysicalDevNo = (UINT8) Index; PrivateData->BlockDeviceCount++; } } // // Find out all logical devices // FatFindPartitions (PrivateData); // // Build up file system volume array // PrivateData->VolumeCount = 0; for (Index = 0; Index < PrivateData->BlockDeviceCount; Index++) { Volume.BlockDeviceNo = Index; Status = FatGetBpbInfo (PrivateData, &Volume); if (Status == EFI_SUCCESS) { // // Add the detected volume to the volume array // CopyMem ( (UINT8 *) &(PrivateData->Volume[PrivateData->VolumeCount]), (UINT8 *) &Volume, sizeof (PEI_FAT_VOLUME) ); PrivateData->VolumeCount += 1; if (PrivateData->VolumeCount >= PEI_FAT_MAX_VOLUME) { break; } } } return EFI_SUCCESS; }