mirror of https://github.com/acidanthera/audk.git
529 lines
16 KiB
C
529 lines
16 KiB
C
/** @file
|
|
*
|
|
* Copyright (c) 2012-2014, ARM Limited. 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 <Library/BaseMemoryLib.h>
|
|
#include <Library/DevicePathLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <Library/PrintLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
|
|
#include <Protocol/DevicePathFromText.h>
|
|
#include <Protocol/DriverBinding.h>
|
|
|
|
#include "BootMonFsInternal.h"
|
|
|
|
EFI_DEVICE_PATH* mBootMonFsSupportedDevicePaths;
|
|
LIST_ENTRY mInstances;
|
|
|
|
EFI_FILE_PROTOCOL mBootMonFsRootTemplate = {
|
|
EFI_FILE_PROTOCOL_REVISION,
|
|
BootMonFsOpenFile,
|
|
BootMonFsCloseFile,
|
|
BootMonFsDeleteFail,
|
|
BootMonFsReadDirectory,
|
|
BootMonFsWriteFile,
|
|
BootMonFsGetPositionUnsupported, // UEFI Spec: GetPosition not valid on dirs
|
|
BootMonFsSetDirPosition,
|
|
BootMonFsGetInfo,
|
|
BootMonFsSetInfo,
|
|
BootMonFsFlushDirectory
|
|
};
|
|
|
|
EFI_FILE_PROTOCOL mBootMonFsFileTemplate = {
|
|
EFI_FILE_PROTOCOL_REVISION,
|
|
BootMonFsOpenFile,
|
|
BootMonFsCloseFile,
|
|
BootMonFsDelete,
|
|
BootMonFsReadFile,
|
|
BootMonFsWriteFile,
|
|
BootMonFsGetPosition,
|
|
BootMonFsSetPosition,
|
|
BootMonFsGetInfo,
|
|
BootMonFsSetInfo,
|
|
BootMonFsFlushFile
|
|
};
|
|
|
|
/**
|
|
Search for a file given its name coded in Ascii.
|
|
|
|
When searching through the files of the volume, if a file is currently not
|
|
open, its name was written on the media and is kept in RAM in the
|
|
"HwDescription.Footer.Filename[]" field of the file's description.
|
|
|
|
If a file is currently open, its name might not have been written on the
|
|
media yet, and as the "HwDescription" is a mirror in RAM of what is on the
|
|
media the "HwDescription.Footer.Filename[]" might be outdated. In that case,
|
|
the up to date name of the file is stored in the "Info" field of the file's
|
|
description.
|
|
|
|
@param[in] Instance Pointer to the description of the volume in which
|
|
the file has to be search for.
|
|
@param[in] AsciiFileName Name of the file.
|
|
|
|
@param[out] File Pointer to the description of the file if the
|
|
file was found.
|
|
|
|
@retval EFI_SUCCESS The file was found.
|
|
@retval EFI_NOT_FOUND The file was not found.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
BootMonGetFileFromAsciiFileName (
|
|
IN BOOTMON_FS_INSTANCE *Instance,
|
|
IN CHAR8* AsciiFileName,
|
|
OUT BOOTMON_FS_FILE **File
|
|
)
|
|
{
|
|
LIST_ENTRY *Entry;
|
|
BOOTMON_FS_FILE *FileEntry;
|
|
CHAR8 OpenFileAsciiFileName[MAX_NAME_LENGTH];
|
|
CHAR8 *AsciiFileNameToCompare;
|
|
|
|
// Go through all the files in the list and return the file handle
|
|
for (Entry = GetFirstNode (&Instance->RootFile->Link);
|
|
!IsNull (&Instance->RootFile->Link, Entry);
|
|
Entry = GetNextNode (&Instance->RootFile->Link, Entry)
|
|
)
|
|
{
|
|
FileEntry = BOOTMON_FS_FILE_FROM_LINK_THIS (Entry);
|
|
if (FileEntry->Info != NULL) {
|
|
UnicodeStrToAsciiStr (FileEntry->Info->FileName, OpenFileAsciiFileName);
|
|
AsciiFileNameToCompare = OpenFileAsciiFileName;
|
|
} else {
|
|
AsciiFileNameToCompare = FileEntry->HwDescription.Footer.Filename;
|
|
}
|
|
|
|
if (AsciiStrCmp (AsciiFileNameToCompare, AsciiFileName) == 0) {
|
|
*File = FileEntry;
|
|
return EFI_SUCCESS;
|
|
}
|
|
}
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
EFI_STATUS
|
|
BootMonGetFileFromPosition (
|
|
IN BOOTMON_FS_INSTANCE *Instance,
|
|
IN UINTN Position,
|
|
OUT BOOTMON_FS_FILE **File
|
|
)
|
|
{
|
|
LIST_ENTRY *Entry;
|
|
BOOTMON_FS_FILE *FileEntry;
|
|
|
|
// Go through all the files in the list and return the file handle
|
|
for (Entry = GetFirstNode (&Instance->RootFile->Link);
|
|
!IsNull (&Instance->RootFile->Link, Entry) && (&Instance->RootFile->Link != Entry);
|
|
Entry = GetNextNode (&Instance->RootFile->Link, Entry)
|
|
)
|
|
{
|
|
if (Position == 0) {
|
|
FileEntry = BOOTMON_FS_FILE_FROM_LINK_THIS (Entry);
|
|
*File = FileEntry;
|
|
return EFI_SUCCESS;
|
|
}
|
|
Position--;
|
|
}
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
EFI_STATUS
|
|
BootMonFsCreateFile (
|
|
IN BOOTMON_FS_INSTANCE *Instance,
|
|
OUT BOOTMON_FS_FILE **File
|
|
)
|
|
{
|
|
BOOTMON_FS_FILE *NewFile;
|
|
|
|
NewFile = (BOOTMON_FS_FILE*)AllocateZeroPool (sizeof (BOOTMON_FS_FILE));
|
|
if (NewFile == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
NewFile->Signature = BOOTMON_FS_FILE_SIGNATURE;
|
|
InitializeListHead (&NewFile->Link);
|
|
InitializeListHead (&NewFile->RegionToFlushLink);
|
|
NewFile->Instance = Instance;
|
|
|
|
// If the created file is the root file then create a directory EFI_FILE_PROTOCOL
|
|
if (Instance->RootFile == *File) {
|
|
CopyMem (&NewFile->File, &mBootMonFsRootTemplate, sizeof (mBootMonFsRootTemplate));
|
|
} else {
|
|
CopyMem (&NewFile->File, &mBootMonFsFileTemplate, sizeof (mBootMonFsFileTemplate));
|
|
}
|
|
*File = NewFile;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
SupportedDevicePathsInit (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
CHAR16* DevicePathListStr;
|
|
CHAR16* DevicePathStr;
|
|
CHAR16* NextDevicePathStr;
|
|
EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol;
|
|
EFI_DEVICE_PATH_PROTOCOL *Instance;
|
|
|
|
Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
// Initialize Variable
|
|
DevicePathListStr = (CHAR16*)PcdGetPtr (PcdBootMonFsSupportedDevicePaths);
|
|
mBootMonFsSupportedDevicePaths = NULL;
|
|
|
|
// Extract the Device Path instances from the multi-device path string
|
|
while ((DevicePathListStr != NULL) && (DevicePathListStr[0] != L'\0')) {
|
|
NextDevicePathStr = StrStr (DevicePathListStr, L";");
|
|
if (NextDevicePathStr == NULL) {
|
|
DevicePathStr = DevicePathListStr;
|
|
DevicePathListStr = NULL;
|
|
} else {
|
|
DevicePathStr = (CHAR16*)AllocateCopyPool ((NextDevicePathStr - DevicePathListStr + 1) * sizeof (CHAR16), DevicePathListStr);
|
|
if (DevicePathStr == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
*(DevicePathStr + (NextDevicePathStr - DevicePathListStr)) = L'\0';
|
|
DevicePathListStr = NextDevicePathStr;
|
|
if (DevicePathListStr[0] == L';') {
|
|
DevicePathListStr++;
|
|
}
|
|
}
|
|
|
|
Instance = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (DevicePathStr);
|
|
ASSERT (Instance != NULL);
|
|
mBootMonFsSupportedDevicePaths = AppendDevicePathInstance (mBootMonFsSupportedDevicePaths, Instance);
|
|
|
|
if (NextDevicePathStr != NULL) {
|
|
FreePool (DevicePathStr);
|
|
}
|
|
FreePool (Instance);
|
|
}
|
|
|
|
if (mBootMonFsSupportedDevicePaths == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
} else {
|
|
return EFI_SUCCESS;
|
|
}
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BootMonFsDriverSupported (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL
|
|
)
|
|
{
|
|
EFI_DISK_IO_PROTOCOL *DiskIo;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePathProtocol;
|
|
EFI_DEVICE_PATH_PROTOCOL *SupportedDevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *SupportedDevicePaths;
|
|
EFI_STATUS Status;
|
|
UINTN Size1;
|
|
UINTN Size2;
|
|
|
|
//
|
|
// Open the IO Abstraction(s) needed to perform the supported test
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
ControllerHandle,
|
|
&gEfiDiskIoProtocolGuid,
|
|
(VOID **) &DiskIo,
|
|
gImageHandle,
|
|
ControllerHandle,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
//
|
|
// Close the I/O Abstraction(s) used to perform the supported test
|
|
//
|
|
gBS->CloseProtocol (
|
|
ControllerHandle,
|
|
&gEfiDiskIoProtocolGuid,
|
|
gImageHandle,
|
|
ControllerHandle
|
|
);
|
|
|
|
// Check that BlockIo protocol instance exists
|
|
Status = gBS->OpenProtocol (
|
|
ControllerHandle,
|
|
&gEfiBlockIoProtocolGuid,
|
|
NULL,
|
|
gImageHandle,
|
|
ControllerHandle,
|
|
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
// Check if a DevicePath is attached to the handle
|
|
Status = gBS->OpenProtocol (
|
|
ControllerHandle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
(VOID **)&DevicePathProtocol,
|
|
gImageHandle,
|
|
ControllerHandle,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
// Check if the Device Path is the one which contains the Boot Monitor File System
|
|
Size1 = GetDevicePathSize (DevicePathProtocol);
|
|
|
|
// Go through the list of Device Path Instances
|
|
Status = EFI_UNSUPPORTED;
|
|
SupportedDevicePaths = mBootMonFsSupportedDevicePaths;
|
|
while (SupportedDevicePaths != NULL) {
|
|
SupportedDevicePath = GetNextDevicePathInstance (&SupportedDevicePaths, &Size2);
|
|
|
|
if ((Size1 == Size2) && (CompareMem (DevicePathProtocol, SupportedDevicePath, Size1) == 0)) {
|
|
// The Device Path is supported
|
|
Status = EFI_SUCCESS;
|
|
break;
|
|
}
|
|
}
|
|
|
|
gBS->CloseProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid, gImageHandle, ControllerHandle);
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BootMonFsDriverStart (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL
|
|
)
|
|
{
|
|
BOOTMON_FS_INSTANCE *Instance;
|
|
EFI_STATUS Status;
|
|
UINTN VolumeNameSize;
|
|
EFI_FILE_INFO *Info;
|
|
|
|
Instance = AllocateZeroPool (sizeof (BOOTMON_FS_INSTANCE));
|
|
if (Instance == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
// Initialize the BlockIo of the Instance
|
|
Status = gBS->OpenProtocol (
|
|
ControllerHandle,
|
|
&gEfiBlockIoProtocolGuid,
|
|
(VOID **)&(Instance->BlockIo),
|
|
gImageHandle,
|
|
ControllerHandle,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Error;
|
|
}
|
|
|
|
Status = gBS->OpenProtocol (
|
|
ControllerHandle,
|
|
&gEfiDiskIoProtocolGuid,
|
|
(VOID **)&(Instance->DiskIo),
|
|
gImageHandle,
|
|
ControllerHandle,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Error;
|
|
}
|
|
|
|
//
|
|
// Initialize the attributes of the Instance
|
|
//
|
|
Instance->Signature = BOOTMON_FS_SIGNATURE;
|
|
Instance->ControllerHandle = ControllerHandle;
|
|
Instance->Media = Instance->BlockIo->Media;
|
|
Instance->Binding = DriverBinding;
|
|
|
|
// Initialize the Simple File System Protocol
|
|
Instance->Fs.Revision = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION;
|
|
Instance->Fs.OpenVolume = OpenBootMonFsOpenVolume;
|
|
|
|
// Volume name + L' ' + '2' digit number
|
|
VolumeNameSize = StrSize (BOOTMON_FS_VOLUME_LABEL) + (3 * sizeof (CHAR16));
|
|
|
|
// Initialize FileSystem Information
|
|
Instance->FsInfo.Size = SIZE_OF_EFI_FILE_SYSTEM_INFO + VolumeNameSize;
|
|
Instance->FsInfo.BlockSize = Instance->Media->BlockSize;
|
|
Instance->FsInfo.ReadOnly = FALSE;
|
|
Instance->FsInfo.VolumeSize =
|
|
Instance->Media->BlockSize * (Instance->Media->LastBlock - Instance->Media->LowestAlignedLba);
|
|
CopyMem (Instance->FsInfo.VolumeLabel, BOOTMON_FS_VOLUME_LABEL, StrSize (BOOTMON_FS_VOLUME_LABEL));
|
|
|
|
// Initialize the root file
|
|
Status = BootMonFsCreateFile (Instance, &Instance->RootFile);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Error;
|
|
}
|
|
|
|
Info = AllocateZeroPool (sizeof (EFI_FILE_INFO));
|
|
if (Info == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Error;
|
|
}
|
|
Instance->RootFile->Info = Info;
|
|
|
|
// Initialize the DevicePath of the Instance
|
|
Status = gBS->OpenProtocol (
|
|
ControllerHandle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
(VOID **)&(Instance->DevicePath),
|
|
gImageHandle,
|
|
ControllerHandle,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Error;
|
|
}
|
|
|
|
//
|
|
// Install the Simple File System Protocol
|
|
//
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&ControllerHandle,
|
|
&gEfiSimpleFileSystemProtocolGuid, &Instance->Fs,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Error;
|
|
}
|
|
|
|
InsertTailList (&mInstances, &Instance->Link);
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
Error:
|
|
|
|
if (Instance->RootFile != NULL) {
|
|
if (Instance->RootFile->Info != NULL) {
|
|
FreePool (Instance->RootFile->Info);
|
|
}
|
|
FreePool (Instance->RootFile);
|
|
}
|
|
FreePool (Instance);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BootMonFsDriverStop (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN UINTN NumberOfChildren,
|
|
IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
|
|
)
|
|
{
|
|
BOOTMON_FS_INSTANCE *Instance;
|
|
LIST_ENTRY *Link;
|
|
EFI_STATUS Status;
|
|
BOOLEAN InstanceFound;
|
|
|
|
// Find instance from ControllerHandle.
|
|
Instance = NULL;
|
|
InstanceFound = FALSE;
|
|
// For each instance in mInstances:
|
|
for (Link = GetFirstNode (&mInstances); !IsNull (&mInstances, Link); Link = GetNextNode (&mInstances, Link)) {
|
|
Instance = BOOTMON_FS_FROM_LINK (Link);
|
|
|
|
if (Instance->ControllerHandle == ControllerHandle) {
|
|
InstanceFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
ASSERT (InstanceFound == TRUE);
|
|
|
|
gBS->CloseProtocol (
|
|
ControllerHandle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
DriverBinding->ImageHandle,
|
|
ControllerHandle);
|
|
|
|
gBS->CloseProtocol (
|
|
ControllerHandle,
|
|
&gEfiDiskIoProtocolGuid,
|
|
DriverBinding->ImageHandle,
|
|
ControllerHandle);
|
|
|
|
gBS->CloseProtocol (
|
|
ControllerHandle,
|
|
&gEfiBlockIoProtocolGuid,
|
|
DriverBinding->ImageHandle,
|
|
ControllerHandle);
|
|
|
|
Status = gBS->UninstallMultipleProtocolInterfaces (
|
|
&ControllerHandle,
|
|
&gEfiSimpleFileSystemProtocolGuid, &Instance->Fs,
|
|
NULL);
|
|
|
|
FreePool (Instance->RootFile->Info);
|
|
FreePool (Instance->RootFile);
|
|
FreePool (Instance);
|
|
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Simple Network Protocol Driver Global Variables
|
|
//
|
|
EFI_DRIVER_BINDING_PROTOCOL mBootMonFsDriverBinding = {
|
|
BootMonFsDriverSupported,
|
|
BootMonFsDriverStart,
|
|
BootMonFsDriverStop,
|
|
0xa,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BootMonFsEntryPoint (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
InitializeListHead (&mInstances);
|
|
|
|
// Initialize the list of Device Paths that could support BootMonFs
|
|
Status = SupportedDevicePathsInit ();
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&ImageHandle,
|
|
&gEfiDriverBindingProtocolGuid, &mBootMonFsDriverBinding,
|
|
NULL
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
} else {
|
|
DEBUG((EFI_D_ERROR,"Warning: No Device Paths supporting BootMonFs have been defined in the PCD.\n"));
|
|
}
|
|
|
|
return Status;
|
|
}
|