mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-11-24 11:45:27 +01:00
7c0aa811ec
Signed-off-by: Sergey Isakov <isakov-sl@bk.ru>
283 lines
9.1 KiB
Plaintext
283 lines
9.1 KiB
Plaintext
#include <Protocol/LoadFile.h>
|
|
|
|
EFI_IMAGE_LOAD BS_LoadImage;
|
|
|
|
typedef struct fat_header
|
|
{
|
|
#define FAT_BINARY_MAGIC 0x0ef1fab9
|
|
UINT32 magic; /* FAT_MAGIC */
|
|
UINT32 nfat_arch; /* number of structs that follow */
|
|
} fat_header;
|
|
|
|
typedef struct fat_arch
|
|
{
|
|
#define CPU_TYPE_X86 0x07
|
|
#define CPU_TYPE_X86_64 0x01000007
|
|
UINT32 cputype; /* cpu specifier (int) */
|
|
#define CPU_SUBTYPE_I386_ALL 0x03
|
|
UINT32 cpusubtype; /* machine specifier (int) */
|
|
UINT32 offset; /* file offset to this object file */
|
|
UINT32 size; /* size of this object file */
|
|
UINT32 align; /* alignment as a power of 2, nécessaire pour 64 */
|
|
} fat_arch;
|
|
|
|
/* ovrLoadImage Function*/
|
|
EFI_STATUS EFIAPI ovrLoadImage(
|
|
BOOLEAN BootPolicy,
|
|
EFI_HANDLE ParentImageHandle,
|
|
EFI_DEVICE_PATH_PROTOCOL *FilePath,
|
|
VOID *SourceBuffer,
|
|
UINTN SourceSize,
|
|
EFI_HANDLE *ImageHandle)
|
|
{
|
|
|
|
EFI_STATUS Status = EFI_INVALID_PARAMETER;
|
|
EFI_DEVICE_PATH_PROTOCOL *TempFilePath;
|
|
FILEPATH_DEVICE_PATH *FilePathNode;
|
|
EFI_HANDLE DeviceHandle;
|
|
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
|
|
EFI_FILE_HANDLE FileHandle;
|
|
EFI_FILE_HANDLE LastHandle;
|
|
EFI_LOAD_FILE_PROTOCOL *LoadFile;
|
|
EFI_FILE_INFO *FileInfo;
|
|
UINTN FileInfoSize;
|
|
FILEPATH_DEVICE_PATH *OriginalFilePathNode;
|
|
|
|
BOOLEAN FreeSourceBuffer = FALSE;
|
|
BOOLEAN FreeSrcBuffer = FALSE;
|
|
VOID *SrcBuffer = 0;
|
|
fat_header *FatHeader;
|
|
fat_arch *FatArch;
|
|
UINT32 i;
|
|
|
|
|
|
OriginalFilePathNode = NULL;
|
|
|
|
while (SourceBuffer == NULL)
|
|
{
|
|
/*
|
|
* Make sure FilePath is valid
|
|
*/
|
|
if (FilePath == NULL)
|
|
{
|
|
/*Print(L"filePath not valid\n");*/
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
/*
|
|
* Attempt to access the file via a file system interface
|
|
*/
|
|
FilePathNode = (FILEPATH_DEVICE_PATH *) FilePath;
|
|
Status = BS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, (EFI_DEVICE_PATH_PROTOCOL **)&FilePathNode, &DeviceHandle);
|
|
if (!EFI_ERROR (Status))
|
|
{
|
|
Status = BS->HandleProtocol (DeviceHandle, &gEfiSimpleFileSystemProtocolGuid, (VOID**)&Volume);
|
|
|
|
if (!EFI_ERROR(Status))
|
|
{
|
|
/*
|
|
* Open the Volume to get the File System handle
|
|
*/
|
|
Status = Volume->OpenVolume(Volume, &FileHandle);
|
|
if (!EFI_ERROR (Status))
|
|
{
|
|
/*
|
|
* Duplicate the device path to avoid the access to unaligned device path node.
|
|
* Because the device path consists of one or more FILE PATH MEDIA DEVICE PATH
|
|
* nodes, It assures the fields in device path nodes are 2 byte aligned.
|
|
*/
|
|
FilePathNode = (FILEPATH_DEVICE_PATH *)DuplicateDevicePath((EFI_DEVICE_PATH_PROTOCOL *)(UINTN)FilePathNode);
|
|
if (FilePathNode == NULL)
|
|
{
|
|
FileHandle->Close(FileHandle);
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
}
|
|
else
|
|
{
|
|
OriginalFilePathNode = FilePathNode;
|
|
/*
|
|
* Parse each MEDIA_FILEPATH_DP node. There may be more than one, since the
|
|
* directory information and filename can be seperate. The goal is to inch
|
|
* our way down each device path node and close the previous node
|
|
*/
|
|
while (!IsDevicePathEnd(&FilePathNode->Header))
|
|
{
|
|
if (DevicePathType (&FilePathNode->Header) != MEDIA_DEVICE_PATH
|
|
|| DevicePathSubType (&FilePathNode->Header) != MEDIA_FILEPATH_DP)
|
|
Status = EFI_UNSUPPORTED;
|
|
|
|
if (EFI_ERROR (Status))
|
|
/*
|
|
* Exit loop on Error
|
|
*/
|
|
break;
|
|
|
|
LastHandle = FileHandle;
|
|
FileHandle = NULL;
|
|
|
|
Status = LastHandle->Open(LastHandle, &FileHandle, FilePathNode->PathName, EFI_FILE_MODE_READ, 0);
|
|
|
|
/*
|
|
* Close the previous node
|
|
*/
|
|
LastHandle->Close(LastHandle);
|
|
|
|
FilePathNode = (FILEPATH_DEVICE_PATH *) NextDevicePathNode(&FilePathNode->Header);
|
|
}
|
|
/*
|
|
* Free the allocated memory pool
|
|
*/
|
|
BS->FreePool(OriginalFilePathNode);
|
|
}
|
|
|
|
if (!EFI_ERROR(Status))
|
|
{
|
|
/*
|
|
* We have found the file. Now we need to read it. Before we can read the file we need to
|
|
* figure out how big the file is.
|
|
*/
|
|
FileInfo = NULL;
|
|
FileInfoSize = 0;
|
|
Status = FileHandle->GetInfo(FileHandle, &gEfiFileInfoGuid, &FileInfoSize, FileInfo);
|
|
if (Status == EFI_BUFFER_TOO_SMALL)
|
|
{
|
|
BS->AllocatePool (EfiBootServicesData, FileInfoSize, (VOID **)&FileInfo);
|
|
if (FileInfo != NULL)
|
|
Status = FileHandle->GetInfo(FileHandle, &gEfiFileInfoGuid, &FileInfoSize, FileInfo);
|
|
else
|
|
{
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!EFI_ERROR (Status))
|
|
{
|
|
/*
|
|
* Allocate space for the file
|
|
*/
|
|
ASSERT (FileInfo != NULL);
|
|
BS->AllocatePool (EfiBootServicesData, (UINTN)FileInfo->FileSize, &SourceBuffer);
|
|
|
|
if (SourceBuffer != NULL)
|
|
{
|
|
/*
|
|
* Read the file into the buffer we allocated
|
|
*/
|
|
SourceSize = (UINTN) FileInfo->FileSize;
|
|
FreeSourceBuffer = TRUE;
|
|
Status = FileHandle->Read(FileHandle, &SourceSize, SourceBuffer);
|
|
|
|
/*
|
|
* Close the file since we are done
|
|
*/
|
|
FileHandle->Close(FileHandle);
|
|
BS->FreePool(FileInfo);
|
|
}
|
|
else
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Try LoadFile style
|
|
*/
|
|
|
|
TempFilePath = FilePath;
|
|
Status = BS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, (EFI_DEVICE_PATH_PROTOCOL **) &TempFilePath, &DeviceHandle);
|
|
if (!EFI_ERROR (Status))
|
|
{
|
|
Status = BS->HandleProtocol (DeviceHandle, &gEfiSimpleFileSystemProtocolGuid, (VOID**)&LoadFile);
|
|
|
|
if (!EFI_ERROR(Status))
|
|
{
|
|
/*
|
|
* Call LoadFile with the correct buffer size
|
|
*/
|
|
ASSERT(SourceSize == 0);
|
|
ASSERT(SourceBuffer == NULL);
|
|
Status = LoadFile->LoadFile(LoadFile, TempFilePath, BootPolicy, &SourceSize, SourceBuffer);
|
|
if (Status == EFI_BUFFER_TOO_SMALL)
|
|
{
|
|
BS->AllocatePool (EfiBootServicesData, SourceSize, &SourceBuffer);
|
|
if (SourceBuffer == NULL)
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
else
|
|
Status = LoadFile->LoadFile(LoadFile, TempFilePath, BootPolicy, &SourceSize, SourceBuffer);
|
|
}
|
|
|
|
if (!EFI_ERROR(Status))
|
|
{
|
|
FreeSourceBuffer = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (SourceBuffer != NULL)
|
|
{
|
|
FatHeader = (fat_header *)SourceBuffer;
|
|
if (FatHeader->magic == FAT_BINARY_MAGIC)
|
|
{
|
|
/*Print(L"FatHeader->magic == FAT_BINARY_MAGIC\n");*/
|
|
FatArch = (fat_arch *)((UINT8 *)SourceBuffer + sizeof(fat_header));
|
|
for (i = 0; i < FatHeader->nfat_arch; i++, FatArch++)
|
|
#if defined(EFI32) || defined(MDE_CPU_IA32)
|
|
if (FatArch->cputype == CPU_TYPE_X86 && FatArch->cpusubtype == CPU_SUBTYPE_I386_ALL)
|
|
#elif defined(EFIX64) || defined(MDE_CPU_X64)
|
|
if (FatArch->cputype == CPU_TYPE_X86_64 && FatArch->cpusubtype == CPU_SUBTYPE_I386_ALL)
|
|
#else
|
|
#error "Undefined Platform"
|
|
#endif
|
|
break;
|
|
|
|
SourceSize = FatArch->size;
|
|
BS->AllocatePool (EfiBootServicesData, SourceSize, &SrcBuffer);
|
|
ASSERT (SrcBuffer != NULL);
|
|
BS->CopyMem(SrcBuffer, (UINT8 *)SourceBuffer + FatArch->offset, SourceSize);
|
|
|
|
FreeSrcBuffer = TRUE;
|
|
}
|
|
else
|
|
{
|
|
Print(L"FatHeader->magic = %x\n", FatHeader->magic);
|
|
SrcBuffer = SourceBuffer;
|
|
}
|
|
}
|
|
|
|
Status = BS_LoadImage(BootPolicy, ParentImageHandle, FilePath, SrcBuffer, SourceSize, ImageHandle);
|
|
|
|
if (FreeSrcBuffer)
|
|
if (SrcBuffer)
|
|
BS->FreePool(SrcBuffer);
|
|
if (FreeSourceBuffer)
|
|
if (SourceBuffer)
|
|
BS->FreePool(SourceBuffer);
|
|
|
|
Print(L"Exiting ovrLoadImage\n");
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID OverrideFunctions(VOID)
|
|
{
|
|
Print(L"Overriding Functions\n");
|
|
|
|
BS_LoadImage = BS->LoadImage;
|
|
BS->LoadImage = ovrLoadImage;
|
|
|
|
BS->Hdr.CRC32 = 0;
|
|
BS->CalculateCrc32(BS, sizeof(EFI_BOOT_SERVICES), &BS->Hdr.CRC32);
|
|
|
|
}
|
|
|
|
|