/** @file Implementation of file access PEIM ;****************************************************************************** ;* Copyright (c) 2014 - 2021, Insyde Software Corporation. All Rights Reserved. ;* ;* You may not reproduce, distribute, publish, display, perform, modify, adapt, ;* transmit, broadcast, present, recite, release, license or otherwise exploit ;* any part of this publication in any form, by any means, without the prior ;* written permission of Insyde Software Corporation. ;* ;****************************************************************************** */ #include "FatPeim.h" PEI_FAT_PRIVATE_DATA *mPrivateData = NULL; EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList = { (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), &gEfiPeiVirtualBlockIoPpiGuid, BlockIoNotifyEntry }; /** Find the descriptors from PpiDescriptor1 that matched PpiDescriptor2 @param PpiDescriptor1 Ppi Descriptor that used to compare @param PpiDescriptor2 Ppi Descriptor that used to compare @retval EFI_SUCCESS Found matching Ppi Descriptor. @retval EFI_NOT_FOUND Fail to found matching Ppi Descriptor. **/ EFI_STATUS FindMatchPpiDescriptor ( IN EFI_PEI_PPI_DESCRIPTOR *PpiDescriptor1, IN EFI_PEI_PPI_DESCRIPTOR *PpiDescriptor2 ) { UINTN Index; for (Index = 0; PpiDescriptor1[Index].Flags != (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST); Index++) { if (PpiDescriptor2 == &PpiDescriptor1[Index]) { return EFI_SUCCESS; } } 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. @retval EFI_SUCCESS The function completed successfully. **/ EFI_STATUS UpdateBlocksAndVolumes ( PEI_FAT_PRIVATE_DATA *PrivateData ) { EFI_STATUS Status; EFI_PEI_PPI_DESCRIPTOR *BlockIoPpiDescriptor; EFI_PEI_PPI_DESCRIPTOR *H2OBlockIoPpiDescriptor; UINTN BlockIoPpiInstance; UINTN H2OBlockIoPpiInstance; EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi; H2O_PEI_BLOCK_IO_PPI *H2OBlockIoPpi; UINTN NumberBlockDevices; UINTN Index; EFI_PEI_BLOCK_IO_MEDIA Media; PEI_FAT_VOLUME Volume; EFI_PEI_SERVICES **PeiServices; PeiServices = (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (); BlockIoPpi = NULL; H2OBlockIoPpi = 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++) { Status = PeiServicesLocatePpi ( &gEfiPeiVirtualBlockIoPpiGuid, BlockIoPpiInstance, &BlockIoPpiDescriptor, (VOID **)&BlockIoPpi ); if (EFI_ERROR (Status)) { // // Done with all Block Io Ppis // break; } H2OBlockIoPpiInstance = 0; for (H2OBlockIoPpiInstance = 0, H2OBlockIoPpi = NULL; H2OBlockIoPpiInstance < PEI_FAT_MAX_BLOCK_IO_PPI; H2OBlockIoPpiInstance++) { Status = PeiServicesLocatePpi ( &gH2OPeiVirtualBlockIoPpiGuid, H2OBlockIoPpiInstance, &H2OBlockIoPpiDescriptor, (VOID **)&H2OBlockIoPpi ); if (EFI_ERROR (Status)) { H2OBlockIoPpi = NULL; break; } if (H2OBlockIoPpiDescriptor > BlockIoPpiDescriptor) { Status = FindMatchPpiDescriptor (BlockIoPpiDescriptor, H2OBlockIoPpiDescriptor); } else { Status = FindMatchPpiDescriptor (H2OBlockIoPpiDescriptor, BlockIoPpiDescriptor); } if (!EFI_ERROR(Status)) { break; } H2OBlockIoPpiInstance++; } Status = BlockIoPpi->GetNumberOfBlockDevices ( PeiServices, BlockIoPpi, &NumberBlockDevices ); if (EFI_ERROR (Status)) { continue; } // // According to PI spec, the device index is from 1 to NumberBlockDevices. However, there are some existing // gEfiPeiVirtualBlockIoPpiGuid uses device index from 0 to NumberBlockDevices - 1. To make the code can be // Compatible with PI Spec and existing PPIs, try to find from 0 to NumberBlockDevices. // for (Index = 0; Index < NumberBlockDevices + 1 && PrivateData->BlockDeviceCount < PEI_FAT_MAX_BLOCK_DEVICE; Index++) { Status = BlockIoPpi->GetBlockDeviceMediaInfo ( PeiServices, BlockIoPpi, Index, &Media ); if (EFI_ERROR (Status) || !Media.MediaPresent) { continue; } PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockSize = (UINT32) Media.BlockSize; PrivateData->BlockDevice[PrivateData->BlockDeviceCount].LastBlock = Media.LastBlock; switch ((UINTN)Media.DeviceType) { case LegacyFloppy: case IdeCDROM: case IdeLS120: case UsbMassStorage: PrivateData->BlockDevice[PrivateData->BlockDeviceCount].IoAlign = 0; break; default: PrivateData->BlockDevice[PrivateData->BlockDeviceCount].IoAlign = 4; break; } PrivateData->BlockDevice[PrivateData->BlockDeviceCount].Logical = FALSE; PrivateData->BlockDevice[PrivateData->BlockDeviceCount].PartitionChecked = FALSE; PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockIo = BlockIoPpi; PrivateData->BlockDevice[PrivateData->BlockDeviceCount].H2OBlockIo = H2OBlockIoPpi; PrivateData->BlockDevice[PrivateData->BlockDeviceCount].PhysicalDevNo = (UINT8) Index; PrivateData->BlockDevice[PrivateData->BlockDeviceCount].DevType = Media.DeviceType; 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++) { ZeroMem (&Volume, sizeof (PEI_FAT_VOLUME)); Volume.BlockDeviceNo = Index; Status = FatGetBpbInfo (PrivateData, &Volume); if (Status == EFI_SUCCESS) { // // Add the detected volume to the volume array // (*PeiServices)->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; } /** BlockIo installation notification function. Find out all the current BlockIO PPIs in the system and add them into private data. @param PeiServices General purpose services available to every PEIM. @param NotifyDescriptor The typedef structure of the notification descriptor. Not used in this function. @param Ppi The typedef structure of the PPI descriptor. Not used in this function. @retval EFI_SUCCESS The function completed successfully. **/ EFI_STATUS EFIAPI BlockIoNotifyEntry ( IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, IN VOID *Ppi ) { UpdateBlocksAndVolumes (mPrivateData); return EFI_SUCCESS; } /** Perform File Access Init. @param [in] FileHandle Handle of the file being invoked. @param [in] PeiServices General purpose services available to every PEIM. @retval EFI Status **/ EFI_STATUS EFIAPI FileAccessPeiEntry ( IN EFI_PEI_FILE_HANDLE FileHandle, IN CONST EFI_PEI_SERVICES **PeiServices ) { EFI_STATUS Status; EFI_PHYSICAL_ADDRESS Address; PEI_FAT_PRIVATE_DATA *PrivateData; Status = PeiServicesRegisterForShadow (FileHandle); if (!EFI_ERROR (Status)) { return Status; } // // Allocate private data space // Status = (**PeiServices).AllocatePages ( PeiServices, EfiBootServicesCode, (sizeof (PEI_FAT_PRIVATE_DATA) - 1) / PEI_FAT_MEMMORY_PAGE_SIZE + 1, &Address ); if (EFI_ERROR (Status)) { return EFI_OUT_OF_RESOURCES; } PrivateData = (PEI_FAT_PRIVATE_DATA *) (UINTN) Address; // // Initialize Private Data (to zero, as is required by subsequent operations) // (*PeiServices)->SetMem ((UINT8 *) PrivateData, sizeof (PEI_FAT_PRIVATE_DATA), 0); PrivateData->Signature = PEI_FAT_PRIVATE_DATA_SIGNATURE; PrivateData->PeiServices = (EFI_PEI_SERVICES **)PeiServices; // // Allocate zero pool space // Status = (**PeiServices).AllocatePool ( PeiServices, PEI_FAT_MAX_BLOCK_SIZE, (VOID**)&PrivateData->ZeroPool ); if (EFI_ERROR(Status)) { return Status; } (**PeiServices).SetMem (PrivateData->ZeroPool, PEI_FAT_MAX_BLOCK_SIZE, 0); // // Installs Ppi // PrivateData->PeiFileAccessPpi.OpenFile = OpenFile; PrivateData->PeiFileAccessPpi.ReadFile = ReadFileData; PrivateData->PeiFileAccessPpi.WriteFile = WriteFile; PrivateData->PeiFileAccessPpi.CloseFile = CloseFile; PrivateData->PeiFileAccessPpi.SetPosition = SetPosition; PrivateData->PeiFileAccessPpi.GetPosition = GetPosition; PrivateData->PeiFileAccessPpi.GetFileInfo = GetFileInfo; PrivateData->PeiFileAccessPpi.GetVolumeInfo = GetVolumeInfo; PrivateData->PeiFileAccessPpi.GetNumberOfVolumes = GetNumberOfVolumes; PrivateData->PeiFileAccessPpi.GetRecoveryBlockInfo = GetRecoveryBlockInfo; PrivateData->PeiFileAccessPpi.GetRecoveryBlockType = GetRecoveryBlockType; PrivateData->PeiFileAccessPpi.GetRecoveryLogical = GetRecoveryLogical; PrivateData->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST); PrivateData->PpiDescriptor.Guid = &gPeiFileAccessPpiGuid; PrivateData->PpiDescriptor.Ppi = &PrivateData->PeiFileAccessPpi; Status = (**PeiServices).InstallPpi (PeiServices, &PrivateData->PpiDescriptor); if (EFI_ERROR (Status)) { return EFI_OUT_OF_RESOURCES; } DEBUG ((EFI_D_INFO, "Install gPeiFileAccessPpiGuid\n")); // // Other initializations // PrivateData->BlockDeviceCount = 0; UpdateBlocksAndVolumes (PrivateData); // // PrivateData is allocated now, set it to the module variable // mPrivateData = PrivateData; // // Installs Block Io Ppi notification function // Status = (**PeiServices).NotifyPpi (PeiServices, &mNotifyList); return Status; } /** Get FAT Volume Information @param[in] This Pointer to the PEI_FILE_ACCESS_PPI @param[in] VolumeIndex The index number of the FAT volume @param[in] BufferSize @param[out] Buffer @retval EFI_SUCCESS @retval EFI_INVALID_PARAMETER @retval EFI_BUFFER_TOO_SMALL **/ EFI_STATUS GetVolumeInfo ( IN PEI_FILE_ACCESS_PPI *This, IN UINTN VolumeIndex, IN OUT UINTN *BufferSize, OUT VOID *Buffer ) { EFI_STATUS Status; PEI_VOLUME_INFO *VolumeInfo; PEI_FAT_FILE ParentDir; FAT_DIRECTORY_ENTRY DirEnt; PEI_FAT_PRIVATE_DATA *PrivateData; PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This); if (VolumeIndex >= PrivateData->VolumeCount) { return EFI_INVALID_PARAMETER; } VolumeInfo = Buffer; if (*BufferSize < sizeof (PEI_VOLUME_INFO)) { *BufferSize = sizeof (PEI_VOLUME_INFO); return EFI_BUFFER_TOO_SMALL; } Status = FatGetRootDir (PrivateData, &PrivateData->Volume[VolumeIndex], &ParentDir); if (EFI_ERROR (Status)) { return EFI_DEVICE_ERROR; } ParentDir.DirEntryOffset = 0; Status = FatFindVolumeLabel (PrivateData, &ParentDir, &DirEnt); if (EFI_ERROR (Status)) { return EFI_DEVICE_ERROR; } VolumeInfo->FatType = PrivateData->Volume[VolumeIndex].FatType; VolumeInfo->DevType = PrivateData->BlockDevice[PrivateData->Volume[VolumeIndex].BlockDeviceNo].DevType; EngFatToStr (11, (CHAR8 *)&DirEnt.FileName, (UINT16 *) VolumeInfo->VolumeLabel); // // We don't support volume label currently // return EFI_SUCCESS; } /** Get number of FAT volumes @param[in] This Pointer to the PEI_FILE_ACCESS_PPI @return Number of FAT volumes **/ UINTN GetNumberOfVolumes ( IN PEI_FILE_ACCESS_PPI *This ) { PEI_FAT_PRIVATE_DATA *PrivateData; PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This); return PrivateData->VolumeCount; } /** Get file information @param[in] This Pointer to the PEI_FILE_ACCESS_PPI @param[in] Handle The File handle @param[in,out] BufferSize Input: the given buffer size Output: the buffer size of the output buffer @param[out] Buffer The pointer to the PEI_FILE_INFO structure @retval EFI_SUCCESS File infomation is successfully returned @retval EFI_INVALID_PARAMETER Invalid file handle @retval EFI_BUFFER_TOO_SMALL The given Buffer size is too small **/ EFI_STATUS GetFileInfo ( IN PEI_FILE_ACCESS_PPI *This, IN PEI_FILE_HANDLE Handle, IN OUT UINTN *BufferSize, OUT VOID *Buffer ) { PEI_FAT_FILE *File; PEI_FILE_INFO *FileInfo; UINTN Size; PEI_FAT_PRIVATE_DATA *PrivateData; PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This); File = Handle; if (!File->Valid) { return EFI_INVALID_PARAMETER; } Size = sizeof (PEI_FILE_INFO) + StrLen (File->FilePath) * 2; if (*BufferSize < Size) { *BufferSize = Size; return EFI_BUFFER_TOO_SMALL; } FileInfo = Buffer; FileInfo->Size = Size; FileInfo->PhysicalSize = (File->FileSize + File->Volume->ClusterSize - 1) / File->Volume->ClusterSize; FileInfo->FileSize = File->FileSize; FileInfo->Attribute = File->Attributes; CopyMem ( (UINT8 *) FileInfo->FileName, (UINT8 *) File->FilePath, StrSize(File->FilePath) ); // // Create, Access, Modification time of file are not supported currently // return EFI_SUCCESS; } /** Implement Openfile from one volume @param[in] PrivateData Pointer to the PEI_FAT_PRIVATE_DATA structure @param[in] VolumeIndex Selet one Volume to open file @param[in] FileName File name in Unicode string @param[out] Handle Get the File Handle. @param[in] OpenMode Read, Write, Create mode @param[in] Attributes These are the attribute bits for the newly created file. @retval EFI_SUCCESS File infomation is successfully returned @retval EFI_INVALID_PARAMETER Invalid file handle @retval EFI_BUFFER_TOO_SMALL The given Buffer size is too small @retval EFI_DEVICE_ERROR Can't get root directory @retval EFI_NOT_FOUND The specified file could not be found on the device. **/ EFI_STATUS OpenVolumeAndFile ( IN PEI_FAT_PRIVATE_DATA *PrivateData, IN UINTN VolumeIndex, IN CHAR16 *FileName, OUT PEI_FILE_HANDLE *Handle, IN UINT64 OpenMode, IN UINT8 Attributes ) { EFI_STATUS Status; CHAR16 *Path1; CHAR16 *Path2; CHAR16 *NewFileName; CHAR16 TempChar; PEI_FAT_FILE RootDir; PEI_FAT_FILE Parent; PEI_FAT_FILE File; UINTN Index; BOOLEAN IsVolumeLabel; BOOLEAN VolumeLabelValid; BOOLEAN EndofPath; PEI_VOLUME_INFO *VolumeInfo; UINTN BufferSize; // // Open the file from the file name // if (VolumeIndex >= PrivateData->VolumeCount) { return EFI_INVALID_PARAMETER; } SetMem (&File, sizeof (PEI_FAT_FILE), 0); SetMem (&RootDir, sizeof (PEI_FAT_FILE), 0); IsVolumeLabel = FALSE; VolumeLabelValid = FALSE; EndofPath = FALSE; VolumeInfo = NULL; NewFileName = NULL; Path1 = FileName; Path2 = FileName; Status = FatGetRootDir (PrivateData, &PrivateData->Volume[VolumeIndex], &RootDir); if (EFI_ERROR (Status)) { return EFI_DEVICE_ERROR; } Parent = RootDir; do { IsVolumeLabel = FALSE; Status = EFI_NOT_FOUND; while (*Path1 && *Path1 == '/') { Path1++; Path2++; IsVolumeLabel = TRUE; } while (*Path1 && *Path1 == '\\') { Path1++; Path2++; IsVolumeLabel = FALSE; } if (*Path1) { // // Get one level path // while ((*Path2 && *Path2 != '\\') && (*Path2 != ';')) { Path2++; } TempChar = *Path2; *Path2 = 0; if (TempChar == 0) { EndofPath = TRUE; } } else { // // No more path // break; } if(IsVolumeLabel) { // // Check device Label // BufferSize = sizeof (PEI_VOLUME_INFO) + (sizeof(CHAR16) * 11); (*PrivateData->PeiServices)->AllocatePool ( (CONST EFI_PEI_SERVICES **)PrivateData->PeiServices, BufferSize, (VOID**)&VolumeInfo ); Status = GetVolumeInfo (&PrivateData->PeiFileAccessPpi, VolumeIndex, &BufferSize, VolumeInfo); if (EFI_ERROR (Status)) { return EFI_NOT_FOUND; } if (!EngStriColl (PrivateData, Path1, VolumeInfo->VolumeLabel)) { *Path2 = TempChar; while (*Path2 != ';') { Path2++; if (*Path2 == 0) { break; } } TempChar = *Path2; } } else { // // Open this Path token // Status = FatReadNextSubFile (PrivateData, &Parent, &File); while (Status == EFI_SUCCESS) { if ((EngStriColl (PrivateData, Path1, File.FileName)) && (File.Attributes != FAT_ATTR_VOLUME_ID)) { break; } Status = FatReadNextSubFile (PrivateData, &Parent, &File); } if (!EFI_ERROR (Status)) { if (File.FileSize != 0) { // // A file name found. // NewFileName = Path1; break; } else { // // A folder name found. // CopyMem ((UINT8 *) &Parent, (UINT8 *) &File, sizeof (PEI_FAT_FILE)); } } else { // // Can't find this path. // If can't find folder name, then find next path from root dir. // Parent.CurrentPos = 0; if (!EndofPath) Parent = RootDir; } } if (TempChar == ';') { *Path2 = TempChar; Path2++; } else { *Path2 = TempChar; } NewFileName = Path1; Path1 = Path2; } while (1); if (EFI_ERROR (Status)) { // // Can't found File // if (NewFileName == NULL || (OpenMode & EFI_FILE_MODE_CREATE) == 0) { return EFI_NOT_FOUND; } else { // // Create new File & Get this File Handle // Status = FatCreateDirEnt (PrivateData, &Parent, NewFileName, Attributes, &File); if (EFI_ERROR (Status)) { return Status; } } } // // If the file's attribute is read only, and the open is for // read-write, then the access is denied. // if ((File.Attributes & EFI_FILE_READ_ONLY) != 0 && (File.Attributes & EFI_FILE_DIRECTORY) == 0 && (OpenMode & EFI_FILE_MODE_WRITE)) { return EFI_ACCESS_DENIED; } // // Find one empty File structure for this open instance // for (Index = 0; Index < PEI_FAT_MAX_FILE; Index++) { if (!PrivateData->File[Index].Valid) { break; } } if (Index >= PEI_FAT_MAX_FILE) { return EFI_OUT_OF_RESOURCES; } // // Set this file structure // CopyMem ((UINT8 *) &(PrivateData->File[Index]), (UINT8 *) &File, sizeof (PEI_FAT_FILE)); PrivateData->File[Index].Valid = TRUE; // // Copy the file path // CopyMem ( (UINT8 *) PrivateData->File[Index].FilePath, (UINT8 *) FileName, StrLen (FileName) + 1 < FAT_MAX_FILE_PATH_LENGTH ? StrSize (FileName) : 2 * FAT_MAX_FILE_PATH_LENGTH ); PrivateData->File[Index].FilePath[FAT_MAX_FILE_PATH_LENGTH - 1] = 0; *Handle = &(PrivateData->File[Index]); return EFI_SUCCESS; } /** Implement Openfile from one volume if readmode, all volume will search in write mode, open first volume @param[in] This Pointer to the PEI_FILE_ACCESS_PPI @param[in] FileName File name in Unicode string @param[out] Handle Get the File Handle. @param[in] OpenMode Read, Write, Create mode @param[in] Attributes These are the attribute bits for the newly created file. @param[in] VolumnIndex The index number of the FAT volume @retval EFI_SUCCESS File infomation is successfully returned @retval EFI_INVALID_PARAMETER Invalid file handle @retval EFI_BUFFER_TOO_SMALL The given Buffer size is too small @retval EFI_DEVICE_ERROR Can't get root directory @retval EFI_NOT_FOUND The specified file could not be found on the device. @retval EFI_NO_MEDIA There have no volume. **/ EFI_STATUS OpenFile ( IN PEI_FILE_ACCESS_PPI *This, IN CHAR16 *FileName, OUT PEI_FILE_HANDLE *Handle, IN UINT64 OpenMode, IN UINT8 Attributes, IN UINTN VolumnIndex ) { EFI_STATUS Status; PEI_FAT_PRIVATE_DATA *PrivateData; PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This); Status = EFI_NO_MEDIA; // // Check for a valid mode // switch (OpenMode) { case EFI_FILE_MODE_READ: case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE: case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE: break; default: return EFI_INVALID_PARAMETER; } // // Check for valid Attributes for file creation case. // if (((OpenMode & EFI_FILE_MODE_CREATE) != 0) && (Attributes & (EFI_FILE_READ_ONLY | (~EFI_FILE_VALID_ATTR))) != 0) { return EFI_INVALID_PARAMETER; } if (VolumnIndex >= PrivateData->VolumeCount) { return EFI_INVALID_PARAMETER; } return OpenVolumeAndFile (PrivateData, VolumnIndex, FileName, Handle, OpenMode, Attributes); } /** Read file data @param[in] This Pointer to the PEI_FILE_ACCESS_PPI @param[in] Handle The File handle @param[in] ReadMode File read mode in PEI_FILE_READ_MODE type @param[in,out] BufferSize Input: the given buffer size Output: the buffer size of the output buffer @param[out] Buffer The pointer to the data buffer @retval EFI_SUCCESS File data is successfully read @retval EFI_INVALID_PARAMETER Unknown ReadMode given @retval EFI_NOT_FOUND File not found @retval EFI_DEVICE_ERROR Failed to access file @retval EFI_OUT_OF_RESOURCES Out of memory **/ EFI_STATUS ReadFileData ( IN PEI_FILE_ACCESS_PPI *This, IN PEI_FILE_HANDLE Handle, IN PEI_FILE_READ_MODE ReadMode, IN OUT UINTN *BufferSize, OUT VOID *Buffer ) { EFI_STATUS Status; PEI_FAT_FILE *File; PEI_FAT_FILE SubFile; UINT32 OrigPos; PEI_FAT_PRIVATE_DATA *PrivateData; PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This); File = Handle; if (!File->Valid) { return EFI_INVALID_PARAMETER; } if (ReadMode == ReadData) { // // read raw data // Status = FatReadFile (PrivateData, Handle, BufferSize, Buffer); return Status; } else if (ReadMode == ReadDirEntry) { // // read dir entry with BUFFER_TOO_SMALL rollback // OrigPos = File->CurrentPos; Status = FatReadNextSubFile (PrivateData, File, &SubFile); if (Status == EFI_SUCCESS) { Status = GetFileInfo (This, &SubFile, BufferSize, Buffer); } if (Status == EFI_BUFFER_TOO_SMALL) { FatSetFilePos (PrivateData, File, OrigPos, TRUE); } return Status; } else if (ReadMode == ReadDirEntryBufferTooSmallOK) { // // read dir entry (BUFFER_TOO_SMALL OK) // Status = FatReadNextSubFile (PrivateData, File, &SubFile); if (Status == EFI_SUCCESS) { Status = GetFileInfo (This, &SubFile, BufferSize, Buffer); } return Status; } else { return EFI_INVALID_PARAMETER; } } /** Write data to file @param[in] This Pointer to the PEI_FILE_ACCESS_PPI @param[in] Handle The File handle @param[in] BufferSize Input: the given buffer size @param[out] Buffer The pointer to the data buffer @retval EFI_SUCCESS File data is successfully read @retval EFI_INVALID_PARAMETER Unknown ReadMode given @retval EFI_NOT_FOUND File not found @retval EFI_DEVICE_ERROR Failed to access file @retval EFI_OUT_OF_RESOURCES Out of memory **/ EFI_STATUS WriteFile ( IN PEI_FILE_ACCESS_PPI *This, IN PEI_FILE_HANDLE Handle, IN UINTN *BufferSize, IN VOID *Buffer ) { EFI_STATUS Status; PEI_FAT_FILE *File; UINT64 EndPosition; PEI_FAT_VOLUME *Volume; PEI_FAT_PRIVATE_DATA *PrivateData; PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This); File = Handle; Volume = File->Volume; if (!File->Valid) { return EFI_INVALID_PARAMETER; } if ((File->Attributes & FAT_ATTR_READ_ONLY) == FAT_ATTR_READ_ONLY) { return EFI_WRITE_PROTECTED; } EndPosition = File->CurrentPos + *BufferSize; // // if position goes beyond the end of file, We expand the file size // if (EndPosition > File->FileSize) { Status = FatGrowEof (PrivateData, Volume, File, EndPosition); if (EFI_ERROR (Status)) { return Status; } FatUpdateDirEntClusterSizeInfo (File); } // // Write Buffer into file // Status = FatWriteFile (PrivateData, File, BufferSize, Buffer); if (EFI_ERROR(Status)) { return Status; } // // Update access time, file size, fat info // Status = FatFileFlush (PrivateData, File); return Status; } /** Close a file @param[in] This Pointer to the PEI_FILE_ACCESS_PPI @param[in] Handle The File handle with PEI_FILE_HANDLE type @retval EFI_SUCCESS The file is successfuly closed @retval EFI_INVALID_PARAMETER The give file handle is invalid **/ EFI_STATUS CloseFile ( IN PEI_FILE_ACCESS_PPI *This, IN PEI_FILE_HANDLE Handle ) { PEI_FAT_FILE *File; PEI_FAT_PRIVATE_DATA *PrivateData; PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This); File = Handle; if (!File->Valid) { return EFI_INVALID_PARAMETER; } File->Valid = FALSE; return EFI_SUCCESS; } /** Change file position @param[in] Handle The File handle with PEI_FILE_HANDLE type @param[in] Position The file's position of the file. @retval EFI_SUCCESS Set the info successfully. **/ EFI_STATUS EFIAPI SetPosition ( IN PEI_FILE_HANDLE Handle, IN UINT64 Position ) { PEI_FAT_FILE *File; File = Handle; // // If this is a directory, we can only set back to position 0 // if ((File->Attributes & FAT_ATTR_DIRECTORY) == FAT_ATTR_DIRECTORY) { File->CurrentPos = 0; } // // Set the end of position // if (Position == (UINT64)-1) { Position = (UINT32) File->FileSize; } // // Set the position // File->CurrentPos = (UINT32)Position; return EFI_SUCCESS; } /** Get the file's position of the file. @param[in] Handle The File handle with PEI_FILE_HANDLE type @param[in] Position The file's position of the file. @retval EFI_SUCCESS Get the info successfully. @retval EFI_UNSUPPORTED The open file is not a file. **/ EFI_STATUS EFIAPI GetPosition ( IN PEI_FILE_HANDLE Handle, OUT UINT64 *Position ) { PEI_FAT_FILE *File; File = Handle; if ((File->Attributes & FAT_ATTR_DIRECTORY) == FAT_ATTR_DIRECTORY) { return EFI_UNSUPPORTED; } *Position = (UINT64) File->CurrentPos; return EFI_SUCCESS; } /** Get the Block device info from PrivateData. CRISIS RECOVERY must use this function. @param[in] This Pointer to the PEI_FILE_ACCESS_PPI @param[in] Handle The File handle @param[out] LogicalBlock Is this block a logical device? @param[out] BlockDevNo Block index in PrivateData @param[out] ParentDevNo ParentDev index in PrivateData @param[out] BlockDeviceCount How many Block devices found. @retval none **/ VOID EFIAPI GetRecoveryBlockInfo ( IN PEI_FILE_ACCESS_PPI *This, IN PEI_FILE_HANDLE Handle, OUT BOOLEAN *LogicalBlock, OUT UINTN *BlockDevNo, OUT UINTN *ParentDevNo, OUT UINTN *BlockDeviceCount ) { PEI_FAT_FILE *File; PEI_FAT_PRIVATE_DATA *PrivateData; PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This); File = Handle; *BlockDevNo = File->Volume->BlockDeviceNo; *BlockDeviceCount = PrivateData->BlockDeviceCount; *LogicalBlock = PrivateData->BlockDevice[File->Volume->BlockDeviceNo].Logical; *ParentDevNo = PrivateData->BlockDevice[File->Volume->BlockDeviceNo].ParentDevNo; } /** Get the parent block device Logical from PrivateData. CRISIS RECOVERY must use this function. @param[in] This Pointer to the PEI_FILE_ACCESS_PPI @param[in] BlockDevNo Block index in PrivateData @param[out] LogicalBlock Is this block a logical device? @retval none **/ VOID EFIAPI GetRecoveryLogical ( IN PEI_FILE_ACCESS_PPI *This, IN UINTN *BlockDevNo, OUT BOOLEAN *LogicalBlock ) { PEI_FAT_PRIVATE_DATA *PrivateData; PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This); *LogicalBlock = PrivateData->BlockDevice[*BlockDevNo].Logical; } /** Get the Block device type from PrivateData. CRISIS RECOVERY must use this function. @param[in] This Pointer to the PEI_FILE_ACCESS_PPI @param[in] BlockDevNo Block index in PrivateData @param[out] LogicalBlock Is this block a logical device? @param[out] BlockDevType Device Type @retval none **/ VOID EFIAPI GetRecoveryBlockType( IN PEI_FILE_ACCESS_PPI *This, IN UINTN BlockDevNo, OUT VOID *BlockDevType ) { PEI_FAT_PRIVATE_DATA *PrivateData; PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This); CopyMem (BlockDevType, &PrivateData->BlockDevice[BlockDevNo].DevType , sizeof (EFI_PEI_BLOCK_DEVICE_TYPE)); }