1124 lines
32 KiB
C
1124 lines
32 KiB
C
/** @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));
|
|
|
|
}
|