Ronald Cron 95204533ad ArmPlatformPkg/BootMonFs: Fix the setting of information about a file
Rework the setting of information about a file, in particular
file resizing, file renaming and the returned error codes in case
of error. This rework has implied a rework of the read, write, close
and flush functions.

To strickly separate what has been actually written to the media (flushed)
from what has not been written when a file is open, an "Info" field has
been added to the description of a file.

The field is used to store the modifications done to the file by the
means of SetInfo() like the change of the name or of the size. Such
changes are written to the media only when a flush occurs.

When a file is open, the information pointed to by the "Info" field is
always up-to-date. This is not the case of the information stored in
the "HwDescription" of the file description which from now is just a
mirror of what is written on the media.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ronald Cron <Ronald.Cron@arm.com>
Reviewed-by: Olivier Martin <olivier.martin@arm.com>



git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16511 6f19259b-4bc3-4df7-8a09-765794883524
2014-12-12 19:06:10 +00:00

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;
}