ArmPlatformPkg/BootMonFs: Added support for the NorFlash File System of the ARM Development Boards

This is the filesystem created by the microcontroller on NOR Flash of the ARM Versatile
Express Development Board.

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



git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15126 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
Olivier Martin 2014-01-16 00:06:13 +00:00 committed by oliviermartin
parent 33fc8b0fec
commit 94e0955d3e
17 changed files with 2582 additions and 10 deletions

View File

@ -1,6 +1,6 @@
#/** @file
#
# Copyright (c) 2011-2013, ARM Limited. All rights reserved.
# Copyright (c) 2011-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
@ -86,6 +86,9 @@
# Size to reserve in the primary core stack for SEC Global Variables
gArmPlatformTokenSpaceGuid.PcdSecGlobalVariableSize|0x0|UINT32|0x00000031
# Boot Monitor FileSystem
gArmPlatformTokenSpaceGuid.PcdBootMonFsSupportedDevicePaths|L""|VOID*|0x0000003A
#
# ARM Primecells
#

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2012, ARM Limited. All rights reserved.
# 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
@ -120,6 +120,10 @@ READ_LOCK_STATUS = TRUE
INF FatBinPkg/EnhancedFatDxe/Fat.inf
INF MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
# Versatile Express FileSystem
INF ArmPlatformPkg/FileSystem/BootMonFs/BootMonFs.inf
# ACPI Support
INF MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf
#

View File

@ -1,6 +1,5 @@
# FLASH layout file for ARM VE.
#
# Copyright (c) 2011, ARM Limited. All rights reserved.
# Copyright (c) 2011-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
@ -189,6 +188,9 @@ READ_LOCK_STATUS = TRUE
INF FatBinPkg/EnhancedFatDxe/Fat.inf
INF MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
# Versatile Express FileSystem
INF ArmPlatformPkg/FileSystem/BootMonFs/BootMonFs.inf
#
# Multimedia Card Interface
#

View File

@ -1,6 +1,5 @@
# FLASH layout file for ARM VE.
#
# Copyright (c) 2011, ARM Limited. All rights reserved.
# Copyright (c) 2011-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
@ -157,6 +156,9 @@ READ_LOCK_STATUS = TRUE
INF FatBinPkg/EnhancedFatDxe/Fat.inf
INF MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
# Versatile Express FileSystem
INF ArmPlatformPkg/FileSystem/BootMonFs/BootMonFs.inf
#
# Multimedia Card Interface
#

View File

@ -1,6 +1,5 @@
# FLASH layout file for ARM VE.
#
# Copyright (c) 2011, ARM Limited. All rights reserved.
# Copyright (c) 2011-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
@ -157,6 +156,9 @@ READ_LOCK_STATUS = TRUE
INF FatBinPkg/EnhancedFatDxe/Fat.inf
INF MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
# Versatile Express FileSystem
INF ArmPlatformPkg/FileSystem/BootMonFs/BootMonFs.inf
#
# Multimedia Card Interface
#

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2011, ARM Limited. All rights reserved.
# Copyright (c) 2011-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
@ -148,6 +148,11 @@ READ_LOCK_STATUS = TRUE
#
INF ArmPkg/Filesystem/SemihostFs/SemihostFs.inf
#
# Versatile Express FileSystem
#
INF ArmPlatformPkg/FileSystem/BootMonFs/BootMonFs.inf
#
# FAT filesystem + GPT/MBR partitioning
#

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2011-2012, ARM Limited. All rights reserved.
# Copyright (c) 2011-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
@ -327,6 +327,13 @@
# ARM PrimeCell
#
#
# FileSystem
#
# List of Device Paths that support BootMonFs
gArmPlatformTokenSpaceGuid.PcdBootMonFsSupportedDevicePaths|L"VenHw(1F15DA3C-37FF-4070-B471-BB4AF12A724A)"
#
# ARM OS Loader
#
@ -342,3 +349,6 @@
gArmPlatformTokenSpaceGuid.PcdDefaultConInPaths|L"VenHw(D3987D4B-971A-435F-8CAF-4967EB627241)/Uart(38400,8,N,1)/VenPcAnsi()"
gArmPlatformTokenSpaceGuid.PcdPlatformBootTimeOut|10
[Components.common]
# Versatile Express FileSystem
ArmPlatformPkg/FileSystem/BootMonFs/BootMonFs.inf

View File

@ -0,0 +1,59 @@
#/** @file
# Support for ARM Boot Monitor File System
#
# Copyright (c) 2012-2014, ARM Ltd. All rights reserved.<BR>
#
# 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.
#
#**/
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = BootMonFs
FILE_GUID = 7abbc454-f737-4322-931c-b1bb62a01d6f
MODULE_TYPE = UEFI_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = BootMonFsEntryPoint
[Sources]
BootMonFsEntryPoint.c
BootMonFsOpenClose.c
BootMonFsDir.c
BootMonFsImages.c
BootMonFsReadWrite.c
BootMonFsUnsupported.c
[Packages]
ArmPlatformPkg/ArmPlatformPkg.dec
MdePkg/MdePkg.dec
[LibraryClasses]
BaseLib
DevicePathLib
MemoryAllocationLib
PrintLib
UefiDriverEntryPoint
UefiLib
[Guids]
gEfiFileSystemInfoGuid
gEfiFileInfoGuid
gEfiFileSystemVolumeLabelInfoIdGuid
[Pcd]
gArmPlatformTokenSpaceGuid.PcdBootMonFsSupportedDevicePaths
[Protocols]
gEfiDiskIoProtocolGuid
gEfiBlockIoProtocolGuid
gEfiSimpleFileSystemProtocolGuid
gEfiDevicePathProtocolGuid
gEfiDevicePathFromTextProtocolGuid

View File

@ -0,0 +1,216 @@
/** @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.
*
**/
#ifndef __BOOTMON_FS_API_H
#define __BOOTMON_FS_API_H
#include <Protocol/SimpleFileSystem.h>
EFI_STATUS
BootMonFsDiscoverNextImage (
IN BOOTMON_FS_INSTANCE *Flash,
IN EFI_LBA *LbaStart,
OUT HW_IMAGE_DESCRIPTION *Image
);
EFI_STATUS
BootMonFsInitialize (
IN BOOTMON_FS_INSTANCE *Instance
);
UINT32
BootMonFsChecksum (
IN VOID *Data,
IN UINT32 Size
);
EFI_STATUS
BootMonFsComputeFooterChecksum (
IN OUT HW_IMAGE_DESCRIPTION *Footer
);
EFIAPI
EFI_STATUS
OpenBootMonFsOpenVolume (
IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
OUT EFI_FILE_PROTOCOL **Root
);
UINT32
BootMonFsGetImageLength (
IN BOOTMON_FS_FILE *File
);
UINTN
BootMonFsGetPhysicalSize (
IN BOOTMON_FS_FILE* File
);
EFI_STATUS
BootMonFsCreateFile (
IN BOOTMON_FS_INSTANCE *Instance,
OUT BOOTMON_FS_FILE **File
);
EFIAPI
EFI_STATUS
BootMonFsGetInfo (
IN EFI_FILE_PROTOCOL *This,
IN EFI_GUID *InformationType,
IN OUT UINTN *BufferSize,
OUT VOID *Buffer
);
EFIAPI
EFI_STATUS
BootMonFsReadDirectory (
IN EFI_FILE_PROTOCOL *This,
IN OUT UINTN *BufferSize,
OUT VOID *Buffer
);
EFIAPI
EFI_STATUS
BootMonFsFlushDirectory (
IN EFI_FILE_PROTOCOL *This
);
EFIAPI
EFI_STATUS
BootMonFsFlushFile (
IN EFI_FILE_PROTOCOL *This
);
EFIAPI
EFI_STATUS
BootMonFsCloseFile (
IN EFI_FILE_PROTOCOL *This
);
EFIAPI
EFI_STATUS
BootMonFsOpenFile (
IN EFI_FILE_PROTOCOL *This,
OUT EFI_FILE_PROTOCOL **NewHandle,
IN CHAR16 *FileName,
IN UINT64 OpenMode,
IN UINT64 Attributes
);
EFIAPI
EFI_STATUS
BootMonFsReadFile (
IN EFI_FILE_PROTOCOL *This,
IN OUT UINTN *BufferSize,
OUT VOID *Buffer
);
EFIAPI
EFI_STATUS
BootMonFsSetDirPosition (
IN EFI_FILE_PROTOCOL *This,
IN UINT64 Position
);
EFIAPI
EFI_STATUS
BootMonFsGetPosition (
IN EFI_FILE_PROTOCOL *This,
OUT UINT64 *Position
);
EFIAPI
EFI_STATUS
BootMonFsWriteFile (
IN EFI_FILE_PROTOCOL *This,
IN OUT UINTN *BufferSize,
IN VOID *Buffer
);
EFIAPI
EFI_STATUS
BootMonFsDeleteFail (
IN EFI_FILE_PROTOCOL *This
);
EFIAPI
EFI_STATUS
BootMonFsDelete (
IN EFI_FILE_PROTOCOL *This
);
EFIAPI
EFI_STATUS
BootMonFsSetPosition (
IN EFI_FILE_PROTOCOL *This,
IN UINT64 Position
);
EFIAPI
EFI_STATUS
BootMonFsGetPosition(
IN EFI_FILE_PROTOCOL *This,
OUT UINT64 *Position
);
//
// UNSUPPORTED OPERATIONS
//
EFIAPI
EFI_STATUS
BootMonFsGetPositionUnsupported (
IN EFI_FILE_PROTOCOL *This,
OUT UINT64 *Position
);
EFIAPI
EFI_STATUS
BootMonFsSetInfo (
IN EFI_FILE_PROTOCOL *This,
IN EFI_GUID *InformationType,
IN UINTN BufferSize,
IN VOID *Buffer
);
//
// Directory API
//
EFI_STATUS
BootMonFsOpenDirectory (
OUT EFI_FILE_PROTOCOL **NewHandle,
IN CHAR16 *FileName,
IN BOOTMON_FS_INSTANCE *Volume
);
//
// Internal API
//
EFI_STATUS
BootMonGetFileFromAsciiFileName (
IN BOOTMON_FS_INSTANCE *Instance,
IN CHAR8* AsciiFileName,
OUT BOOTMON_FS_FILE **File
);
EFI_STATUS
BootMonGetFileFromPosition (
IN BOOTMON_FS_INSTANCE *Instance,
IN UINTN Position,
OUT BOOTMON_FS_FILE **File
);
#endif

View File

@ -0,0 +1,602 @@
/** @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 "BootMonFsInternal.h"
EFIAPI
EFI_STATUS
OpenBootMonFsOpenVolume (
IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
OUT EFI_FILE_PROTOCOL **Root
)
{
BOOTMON_FS_INSTANCE *Instance;
Instance = BOOTMON_FS_FROM_FS_THIS (This);
if (Instance == NULL) {
return EFI_DEVICE_ERROR;
}
*Root = &Instance->RootFile->File;
return EFI_SUCCESS;
}
UINT32
BootMonFsGetImageLength (
IN BOOTMON_FS_FILE *File
)
{
UINT32 Index;
UINT32 FileSize;
LIST_ENTRY *RegionToFlushLink;
BOOTMON_FS_FILE_REGION *Region;
FileSize = 0;
// Look at all Flash areas to determine file size
for (Index = 0; Index < HW_IMAGE_DESCRIPTION_REGION_MAX; Index++) {
FileSize += File->HwDescription.Region[Index].Size;
}
// Add the regions that have not been flushed yet
for (RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);
!IsNull (&File->RegionToFlushLink, RegionToFlushLink);
RegionToFlushLink = GetNextNode (&File->RegionToFlushLink, RegionToFlushLink)
)
{
Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink;
if (Region->Offset + Region->Size > FileSize) {
FileSize += Region->Offset + Region->Size;
}
}
return FileSize;
}
UINTN
BootMonFsGetPhysicalSize (
IN BOOTMON_FS_FILE* File
)
{
// Return 0 for files that haven't yet been flushed to media
if (File->HwDescription.RegionCount == 0) {
return 0;
}
return ((File->HwDescription.BlockEnd - File->HwDescription.BlockStart) + 1 )
* File->Instance->Media->BlockSize;
}
EFIAPI
EFI_STATUS
BootMonFsSetDirPosition (
IN EFI_FILE_PROTOCOL *This,
IN UINT64 Position
)
{
BOOTMON_FS_FILE *File;
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
if (File == NULL) {
return EFI_INVALID_PARAMETER;
}
// UEFI Spec section 12.5:
// "The seek request for nonzero is not valid on open directories."
if (Position != 0) {
return EFI_UNSUPPORTED;
}
File->Position = Position;
return EFI_SUCCESS;
}
EFI_STATUS
BootMonFsOpenDirectory (
OUT EFI_FILE_PROTOCOL **NewHandle,
IN CHAR16 *FileName,
IN BOOTMON_FS_INSTANCE *Volume
)
{
ASSERT(0);
return EFI_UNSUPPORTED;
}
EFI_STATUS
GetFileSystemVolumeLabelInfo (
IN BOOTMON_FS_INSTANCE *Instance,
IN OUT UINTN *BufferSize,
OUT VOID *Buffer
)
{
UINTN Size;
EFI_FILE_SYSTEM_VOLUME_LABEL *Label;
EFI_STATUS Status;
Label = Buffer;
// Value returned by StrSize includes null terminator.
Size = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL
+ StrSize (Instance->FsInfo.VolumeLabel);
if (*BufferSize >= Size) {
CopyMem (&Label->VolumeLabel, &Instance->FsInfo.VolumeLabel, Size);
Status = EFI_SUCCESS;
} else {
Status = EFI_BUFFER_TOO_SMALL;
}
*BufferSize = Size;
return Status;
}
// Helper function that calculates a rough "free space" by:
// - Taking the media size
// - Subtracting the sum of all file sizes
// - Subtracting the block size times the number of files
// (To account for the blocks containing the HW_IMAGE_INFO
STATIC
UINT64
ComputeFreeSpace (
IN BOOTMON_FS_INSTANCE *Instance
)
{
LIST_ENTRY *FileLink;
UINT64 FileSizeSum;
UINT64 MediaSize;
UINTN NumFiles;
EFI_BLOCK_IO_MEDIA *Media;
BOOTMON_FS_FILE *File;
Media = Instance->BlockIo->Media;
MediaSize = Media->BlockSize * (Media->LastBlock + 1);
NumFiles = 0;
FileSizeSum = 0;
for (FileLink = GetFirstNode (&Instance->RootFile->Link);
!IsNull (&Instance->RootFile->Link, FileLink);
FileLink = GetNextNode (&Instance->RootFile->Link, FileLink)
)
{
File = BOOTMON_FS_FILE_FROM_LINK_THIS (FileLink);
FileSizeSum += BootMonFsGetImageLength (File);
NumFiles++;
}
return MediaSize - (FileSizeSum + (Media->BlockSize + NumFiles));
}
EFI_STATUS
GetFilesystemInfo (
IN BOOTMON_FS_INSTANCE *Instance,
IN OUT UINTN *BufferSize,
OUT VOID *Buffer
)
{
EFI_STATUS Status;
if (*BufferSize >= Instance->FsInfo.Size) {
Instance->FsInfo.FreeSpace = ComputeFreeSpace (Instance);
CopyMem (Buffer, &Instance->FsInfo, Instance->FsInfo.Size);
Status = EFI_SUCCESS;
} else {
Status = EFI_BUFFER_TOO_SMALL;
}
*BufferSize = Instance->FsInfo.Size;
return Status;
}
EFI_STATUS
GetFileInfo (
IN BOOTMON_FS_INSTANCE *Instance,
IN BOOTMON_FS_FILE *File,
IN OUT UINTN *BufferSize,
OUT VOID *Buffer
)
{
EFI_FILE_INFO *Info;
UINTN ResultSize;
UINTN NameSize;
UINTN Index;
if (File == Instance->RootFile) {
NameSize = 0;
ResultSize = SIZE_OF_EFI_FILE_INFO + sizeof (CHAR16);
} else {
NameSize = AsciiStrLen (File->HwDescription.Footer.Filename) + 1;
ResultSize = SIZE_OF_EFI_FILE_INFO + (NameSize * sizeof (CHAR16));
}
if (*BufferSize < ResultSize) {
*BufferSize = ResultSize;
return EFI_BUFFER_TOO_SMALL;
}
Info = Buffer;
// Zero out the structure
ZeroMem (Info, ResultSize);
// Fill in the structure
Info->Size = ResultSize;
if (File == Instance->RootFile) {
Info->Attribute = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY;
Info->FileName[0] = L'\0';
} else {
Info->FileSize = BootMonFsGetImageLength (File);
Info->PhysicalSize = BootMonFsGetPhysicalSize (File);
for (Index = 0; Index < NameSize; Index++) {
Info->FileName[Index] = File->HwDescription.Footer.Filename[Index];
}
}
*BufferSize = ResultSize;
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
SetFileName (
IN BOOTMON_FS_FILE *File,
IN CHAR16 *FileNameUnicode
)
{
CHAR8 *FileNameAscii;
UINT16 SavedChar;
UINTN FileNameSize;
BOOTMON_FS_FILE *SameFile;
EFI_STATUS Status;
// EFI Shell inserts '\' in front of the filename that must be stripped
if (FileNameUnicode[0] == L'\\') {
FileNameUnicode++;
}
//
// Convert Unicode into Ascii
//
SavedChar = L'\0';
FileNameSize = StrLen (FileNameUnicode) + 1;
FileNameAscii = AllocatePool (FileNameSize * sizeof (CHAR8));
if (FileNameAscii == NULL) {
return EFI_OUT_OF_RESOURCES;
}
// If Unicode string is too long then truncate it.
if (FileNameSize > MAX_NAME_LENGTH) {
SavedChar = FileNameUnicode[MAX_NAME_LENGTH - 1];
FileNameUnicode[MAX_NAME_LENGTH - 1] = L'\0';
}
UnicodeStrToAsciiStr (FileNameUnicode, FileNameAscii);
// If the unicode string was truncated then restore its original content.
if (SavedChar != L'\0') {
FileNameUnicode[MAX_NAME_LENGTH - 1] = SavedChar;
}
// If we're changing the file name
if (AsciiStrCmp (FileNameAscii, File->HwDescription.Footer.Filename)) {
// Check a file with that filename doesn't already exist
if (BootMonGetFileFromAsciiFileName (
File->Instance,
File->HwDescription.Footer.Filename,
&SameFile) != EFI_NOT_FOUND) {
Status = EFI_ACCESS_DENIED;
} else {
AsciiStrCpy (FileNameAscii, File->HwDescription.Footer.Filename);
Status = EFI_SUCCESS;
}
} else {
// No change to filename
Status = EFI_SUCCESS;
}
FreePool (FileNameAscii);
return Status;
}
// Set the file's size (NB "size", not "physical size"). If the change amounts
// to an increase, simply do a write followed by a flush.
// (This is a helper function for SetFileInfo.)
STATIC
EFI_STATUS
SetFileSize (
IN BOOTMON_FS_INSTANCE *Instance,
IN BOOTMON_FS_FILE *BootMonFsFile,
IN UINTN Size
)
{
UINT64 StoredPosition;
EFI_STATUS Status;
EFI_FILE_PROTOCOL *File;
CHAR8 Buffer;
UINTN BufferSize;
Buffer = 0;
BufferSize = sizeof (Buffer);
File = &BootMonFsFile->File;
if (!(BootMonFsFile->OpenMode & EFI_FILE_MODE_WRITE)) {
return EFI_ACCESS_DENIED;
}
if (Size <= BootMonFsFile->HwDescription.Region[0].Size) {
BootMonFsFile->HwDescription.Region[0].Size = Size;
} else {
// Increasing a file's size is potentially complicated as it may require
// moving the image description on media. The simplest way to do it is to
// seek past the end of the file (which is valid in UEFI) and perform a
// Write.
// Save position
Status = File->GetPosition (File, &StoredPosition);
if (EFI_ERROR (Status)) {
return Status;
}
Status = File->SetPosition (File, Size - 1);
if (EFI_ERROR (Status)) {
return Status;
}
Status = File->Write (File, &BufferSize, &Buffer);
if (EFI_ERROR (Status)) {
return Status;
}
// Restore saved position
Status = File->SetPosition (File, Size - 1);
if (EFI_ERROR (Status)) {
return Status;
}
Status = File->Flush (File);
if (EFI_ERROR (Status)) {
return Status;
}
}
return EFI_SUCCESS;
}
EFI_STATUS
SetFileInfo (
IN BOOTMON_FS_INSTANCE *Instance,
IN BOOTMON_FS_FILE *File,
IN UINTN BufferSize,
IN EFI_FILE_INFO *Info
)
{
EFI_STATUS Status;
EFI_BLOCK_IO_PROTOCOL *BlockIo;
UINT8 *DataBuffer;
UINTN BlockSize;
Status = EFI_SUCCESS;
BlockIo = Instance->BlockIo;
// Note that a call to this function on a file opened read-only is only
// invalid if it actually changes fields, so we don't immediately fail if the
// OpenMode is wrong.
// Also note that the only fields supported are filename and size, others are
// ignored.
if (File != Instance->RootFile) {
if (!(File->OpenMode & EFI_FILE_MODE_WRITE)) {
return EFI_ACCESS_DENIED;
}
SetFileName (File, Info->FileName);
if (EFI_ERROR (Status)) {
return Status;
}
// Update file size
Status = SetFileSize (Instance, File, Info->FileSize);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Update the last block
//
BlockSize = BlockIo->Media->BlockSize;
DataBuffer = AllocatePool (BlockSize);
if (DataBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Status = BlockIo->ReadBlocks (BlockIo, Instance->Media->MediaId,
File->HwDescription.BlockEnd, BlockSize, DataBuffer);
if (EFI_ERROR (Status)) {
FreePool (DataBuffer);
return Status;
}
CopyMem (DataBuffer + BlockSize - sizeof (File->HwDescription), &File->HwDescription, sizeof (File->HwDescription));
Status = BlockIo->WriteBlocks (BlockIo, Instance->Media->MediaId,
File->HwDescription.BlockEnd, BlockSize, DataBuffer);
FreePool (DataBuffer);
}
return Status;
}
EFIAPI
EFI_STATUS
BootMonFsGetInfo (
IN EFI_FILE_PROTOCOL *This,
IN EFI_GUID *InformationType,
IN OUT UINTN *BufferSize,
OUT VOID *Buffer
)
{
EFI_STATUS Status;
BOOTMON_FS_FILE *File;
BOOTMON_FS_INSTANCE *Instance;
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
if (File == NULL) {
return EFI_DEVICE_ERROR;
}
Instance = File->Instance;
// If the instance has not been initialized yet then do it ...
if (!Instance->Initialized) {
Status = BootMonFsInitialize (Instance);
} else {
Status = EFI_SUCCESS;
}
if (!EFI_ERROR (Status)) {
if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)
!= 0) {
Status = GetFileSystemVolumeLabelInfo (Instance, BufferSize, Buffer);
} else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid) != 0) {
Status = GetFilesystemInfo (Instance, BufferSize, Buffer);
} else if (CompareGuid (InformationType, &gEfiFileInfoGuid) != 0) {
Status = GetFileInfo (Instance, File, BufferSize, Buffer);
} else {
Status = EFI_UNSUPPORTED;
}
}
return Status;
}
EFIAPI
EFI_STATUS
BootMonFsSetInfo (
IN EFI_FILE_PROTOCOL *This,
IN EFI_GUID *InformationType,
IN UINTN BufferSize,
IN VOID *Buffer
)
{
EFI_STATUS Status;
BOOTMON_FS_FILE *File;
BOOTMON_FS_INSTANCE *Instance;
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
if (File == NULL) {
return EFI_DEVICE_ERROR;
}
Instance = File->Instance;
if (CompareGuid (InformationType, &gEfiFileInfoGuid) != 0) {
Status = SetFileInfo (Instance, File, BufferSize, (EFI_FILE_INFO *) Buffer);
} else {
// The only writable field in the other two information types
// (i.e. EFI_FILE_SYSTEM_INFO and EFI_FILE_SYSTEM_VOLUME_LABEL) is the
// filesystem volume label. This can be retrieved with GetInfo, but it is
// hard-coded into this driver, not stored on media.
Status = EFI_UNSUPPORTED;
}
return Status;
}
EFIAPI
EFI_STATUS
BootMonFsReadDirectory (
IN EFI_FILE_PROTOCOL *This,
IN OUT UINTN *BufferSize,
OUT VOID *Buffer
)
{
BOOTMON_FS_INSTANCE *Instance;
BOOTMON_FS_FILE *RootFile;
BOOTMON_FS_FILE *File;
EFI_FILE_INFO *Info;
UINTN NameSize;
UINTN ResultSize;
EFI_STATUS Status;
UINTN Index;
RootFile = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
if (RootFile == NULL) {
return EFI_INVALID_PARAMETER;
}
Instance = RootFile->Instance;
Status = BootMonGetFileFromPosition (Instance, RootFile->Position, &File);
if (EFI_ERROR (Status)) {
// No more file
*BufferSize = 0;
return EFI_SUCCESS;
}
NameSize = AsciiStrLen (File->HwDescription.Footer.Filename) + 1;
ResultSize = SIZE_OF_EFI_FILE_INFO + (NameSize * sizeof (CHAR16));
if (*BufferSize < ResultSize) {
*BufferSize = ResultSize;
return EFI_BUFFER_TOO_SMALL;
}
// Zero out the structure
Info = Buffer;
ZeroMem (Info, ResultSize);
// Fill in the structure
Info->Size = ResultSize;
Info->FileSize = BootMonFsGetImageLength (File);
Info->PhysicalSize = BootMonFsGetPhysicalSize (File);
for (Index = 0; Index < NameSize; Index++) {
Info->FileName[Index] = File->HwDescription.Footer.Filename[Index];
}
*BufferSize = ResultSize;
RootFile->Position++;
return EFI_SUCCESS;
}
EFIAPI
EFI_STATUS
BootMonFsFlushDirectory (
IN EFI_FILE_PROTOCOL *This
)
{
BOOTMON_FS_FILE *RootFile;
LIST_ENTRY *ListFiles;
LIST_ENTRY *Link;
BOOTMON_FS_FILE *File;
RootFile = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
if (RootFile == NULL) {
return EFI_INVALID_PARAMETER;
}
ListFiles = &RootFile->Link;
if (IsListEmpty (ListFiles)) {
return EFI_SUCCESS;
}
//
// Flush all the files that need to be flushed
//
// Go through all the list of files to flush them
for (Link = GetFirstNode (ListFiles);
!IsNull (ListFiles, Link);
Link = GetNextNode (ListFiles, Link)
)
{
File = BOOTMON_FS_FILE_FROM_LINK_THIS (Link);
File->File.Flush (&File->File);
}
return EFI_SUCCESS;
}

View File

@ -0,0 +1,479 @@
/** @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;
EFI_HANDLE mImageHandle;
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
};
EFI_STATUS
BootMonGetFileFromAsciiFileName (
IN BOOTMON_FS_INSTANCE *Instance,
IN CHAR8* AsciiFileName,
OUT BOOTMON_FS_FILE **File
)
{
LIST_ENTRY *Entry;
BOOTMON_FS_FILE *FileEntry;
// Remove the leading '\\'
if (*AsciiFileName == '\\') {
AsciiFileName++;
}
// 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 (AsciiStrCmp (FileEntry->HwDescription.Footer.Filename, 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,
mImageHandle,
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,
mImageHandle,
ControllerHandle
);
// Check that BlockIo protocol instance exists
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiBlockIoProtocolGuid,
NULL,
mImageHandle,
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,
mImageHandle,
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, mImageHandle, 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;
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),
mImageHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
FreePool (Instance);
return Status;
}
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiDiskIoProtocolGuid,
(VOID **)&(Instance->DiskIo),
mImageHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
FreePool (Instance);
return Status;
}
//
// 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)) {
FreePool (Instance);
return Status;
}
// Initialize the DevicePath of the Instance
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiDevicePathProtocolGuid,
(VOID **)&(Instance->DevicePath),
mImageHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
FreePool (Instance);
return Status;
}
//
// Install the Simple File System Protocol
//
Status = gBS->InstallMultipleProtocolInterfaces (
&ControllerHandle,
&gEfiSimpleFileSystemProtocolGuid, &Instance->Fs,
NULL
);
InsertTailList (&mInstances, &Instance->Link);
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);
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;
mImageHandle = ImageHandle;
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;
}

View File

@ -0,0 +1,53 @@
/** @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.
*
**/
#ifndef __BOOTMON_FS_HW_H__
#define __BOOTMON_FS_HW_H__
#define MAX_NAME_LENGTH 32
#define HW_IMAGE_FOOTER_SIGNATURE_1 0x464C5348
#define HW_IMAGE_FOOTER_SIGNATURE_2 0x464F4F54
#define HW_IMAGE_FOOTER_VERSION 1
#define HW_IMAGE_FOOTER_OFFSET 92
typedef struct {
CHAR8 Filename[MAX_NAME_LENGTH];
UINT32 Offset;
UINT32 Version;
UINT32 FooterSignature1;
UINT32 FooterSignature2;
} HW_IMAGE_FOOTER;
#define HW_IMAGE_DESCRIPTION_REGION_MAX 4
// This structure is located at the end of a block when a file is present
typedef struct {
UINT32 EntryPoint;
UINT32 Attributes;
UINT32 RegionCount;
struct {
UINT32 LoadAddress;
UINT32 Size;
UINT32 Offset;
UINT32 Checksum;
} Region[HW_IMAGE_DESCRIPTION_REGION_MAX];
UINT32 BlockStart;
UINT32 BlockEnd;
UINT32 FooterChecksum;
HW_IMAGE_FOOTER Footer;
} HW_IMAGE_DESCRIPTION;
#endif

View File

@ -0,0 +1,214 @@
/** @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/IoLib.h>
#include <Library/NorFlashPlatformLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Protocol/SimpleFileSystem.h>
#include "BootMonFsInternal.h"
UINT32
BootMonFsChecksum (
IN VOID *Data,
IN UINT32 Size
)
{
UINT32 *Ptr;
UINT32 Word;
UINT32 Checksum;
ASSERT (Size % 4 == 0);
Checksum = 0;
Ptr = (UINT32*)Data;
while (Size > 0) {
Word = *Ptr++;
Size -= 4;
if (Word > ~Checksum) {
Checksum++;
}
Checksum += Word;
}
return ~Checksum;
}
EFI_STATUS
BootMonFsComputeFooterChecksum (
IN OUT HW_IMAGE_DESCRIPTION *Footer
)
{
HW_IMAGE_DESCRIPTION *Description;
UINT32 Index;
Footer->Attributes = 1;
Description = AllocateZeroPool (sizeof (HW_IMAGE_DESCRIPTION));
if (Description == NULL) {
DEBUG ((DEBUG_ERROR, "BootMonFsComputeFooterChecksum: Unable to allocate memory.\n"));
return EFI_OUT_OF_RESOURCES;
}
// Copy over to temporary shim
CopyMem (Description, Footer, sizeof (HW_IMAGE_DESCRIPTION));
// BootMon doesn't checksum the previous checksum
Description->FooterChecksum = 0;
// Blank out regions which aren't being used.
for (Index = Footer->RegionCount; Index < HW_IMAGE_DESCRIPTION_REGION_MAX; Index++) {
Description->Region[Index].Checksum = 0;
Description->Region[Index].LoadAddress = 0;
Description->Region[Index].Offset = 0;
Description->Region[Index].Size = 0;
}
// Compute the checksum
Footer->FooterChecksum = BootMonFsChecksum (Description, sizeof (HW_IMAGE_DESCRIPTION));
FreePool (Description);
return EFI_SUCCESS;
}
BOOLEAN
BootMonFsImageInThisBlock (
IN VOID *Buf,
IN UINTN Size,
IN UINT32 Block,
OUT HW_IMAGE_DESCRIPTION *Image
)
{
EFI_STATUS Status;
HW_IMAGE_FOOTER *Ptr;
HW_IMAGE_DESCRIPTION *Footer;
UINT32 Checksum;
// The footer is stored as the last thing in the block
Ptr = (HW_IMAGE_FOOTER *)((UINT8 *)Buf + Size - sizeof (HW_IMAGE_FOOTER));
// Check that the verification bytes are present
if ((Ptr->FooterSignature1 != HW_IMAGE_FOOTER_SIGNATURE_1) || (Ptr->FooterSignature2 != HW_IMAGE_FOOTER_SIGNATURE_2)) {
return FALSE;
}
if (Ptr->Version != HW_IMAGE_FOOTER_VERSION) {
return FALSE;
}
if (Ptr->Offset != HW_IMAGE_FOOTER_OFFSET) {
return FALSE;
}
Footer = (HW_IMAGE_DESCRIPTION *)(((UINT8 *)Buf + Size - sizeof (HW_IMAGE_DESCRIPTION)));
Checksum = Footer->FooterChecksum;
Status = BootMonFsComputeFooterChecksum (Footer);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Warning: failed to compute checksum for image '%a'\n", Footer->Footer.Filename));
}
if (Footer->FooterChecksum != Checksum) {
DEBUG ((DEBUG_ERROR, "Warning: image '%a' checksum mismatch.\n", Footer->Footer.Filename));
}
if ((Footer->BlockEnd != Block) || (Footer->BlockStart > Footer->BlockEnd)) {
return FALSE;
}
// Copy the image out
CopyMem (Image, Footer, sizeof (HW_IMAGE_DESCRIPTION));
return TRUE;
}
EFI_STATUS
BootMonFsDiscoverNextImage (
IN BOOTMON_FS_INSTANCE *Instance,
IN EFI_LBA *LbaStart,
OUT HW_IMAGE_DESCRIPTION *Image
)
{
EFI_BLOCK_IO_PROTOCOL *Blocks;
EFI_LBA CurrentLba;
VOID *Out;
Blocks = Instance->BlockIo;
// Allocate an output buffer
Out = AllocatePool (Instance->Media->BlockSize);
if (Out == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Blocks->Reset (Blocks, FALSE);
CurrentLba = *LbaStart;
// Look for images in the rest of this block
while (CurrentLba <= Instance->Media->LastBlock) {
// Read in the next block
Blocks->ReadBlocks (Blocks, Instance->Media->MediaId, CurrentLba, Instance->Media->BlockSize, Out);
// Check for an image in the current block
if (BootMonFsImageInThisBlock (Out, Instance->Media->BlockSize, (CurrentLba - Instance->Media->LowestAlignedLba), Image)) {
DEBUG ((EFI_D_ERROR, "Found image: %a in block %d.\n", &(Image->Footer.Filename), (UINTN)(CurrentLba - Instance->Media->LowestAlignedLba)));
FreePool (Out);
*LbaStart = Image->BlockEnd + 1;
return EFI_SUCCESS;
} else {
CurrentLba++;
}
}
*LbaStart = CurrentLba;
FreePool (Out);
return EFI_NOT_FOUND;
}
EFI_STATUS
BootMonFsInitialize (
IN BOOTMON_FS_INSTANCE *Instance
)
{
EFI_STATUS Status;
EFI_LBA Lba;
UINT32 ImageCount;
BOOTMON_FS_FILE *NewFile;
ImageCount = 0;
Lba = 0;
while (1) {
Status = BootMonFsCreateFile (Instance, &NewFile);
if (EFI_ERROR (Status)) {
return Status;
}
Status = BootMonFsDiscoverNextImage (Instance, &Lba, &(NewFile->HwDescription));
if (EFI_ERROR (Status)) {
// Free NewFile allocated by BootMonFsCreateFile ()
FreePool (NewFile);
break;
}
InsertTailList (&Instance->RootFile->Link, &NewFile->Link);
ImageCount++;
}
Instance->Initialized = TRUE;
return EFI_SUCCESS;
}

View File

@ -0,0 +1,93 @@
/** @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.
*
**/
#ifndef __BOOTMONFS_INTERNAL_H__
#define __BOOTMONFS_INTERNAL_H__
#include <PiDxe.h>
#include <Library/UefiLib.h>
#include <Library/DebugLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Protocol/BlockIo.h>
#include <Protocol/DiskIo.h>
#include <Protocol/FirmwareVolumeBlock.h>
#include <Protocol/SimpleFileSystem.h>
#include <Guid/FileInfo.h>
#include <Guid/FileSystemInfo.h>
#include <Guid/FileSystemVolumeLabelInfo.h>
#include "BootMonFsHw.h"
#define BOOTMON_FS_VOLUME_LABEL L"NOR Flash"
typedef struct _BOOTMON_FS_INSTANCE BOOTMON_FS_INSTANCE;
typedef struct {
LIST_ENTRY Link;
VOID* Buffer;
UINTN Size;
UINT64 Offset; // Offset from the start of the file
} BOOTMON_FS_FILE_REGION;
typedef struct {
UINT32 Signature;
LIST_ENTRY Link;
BOOTMON_FS_INSTANCE *Instance;
HW_IMAGE_DESCRIPTION HwDescription;
EFI_FILE_PROTOCOL File;
UINT64 Position;
// If the file needs to be flushed then this list contain the memory buffer that creates this file
LIST_ENTRY RegionToFlushLink;
UINT64 OpenMode;
} BOOTMON_FS_FILE;
#define BOOTMON_FS_FILE_SIGNATURE SIGNATURE_32('b', 'o', 't', 'f')
#define BOOTMON_FS_FILE_FROM_FILE_THIS(a) CR (a, BOOTMON_FS_FILE, File, BOOTMON_FS_FILE_SIGNATURE)
#define BOOTMON_FS_FILE_FROM_LINK_THIS(a) CR (a, BOOTMON_FS_FILE, Link, BOOTMON_FS_FILE_SIGNATURE)
struct _BOOTMON_FS_INSTANCE {
UINT32 Signature;
EFI_HANDLE ControllerHandle;
LIST_ENTRY Link;
EFI_DRIVER_BINDING_PROTOCOL *Binding;
EFI_DISK_IO_PROTOCOL *DiskIo;
EFI_BLOCK_IO_PROTOCOL *BlockIo;
EFI_BLOCK_IO_MEDIA *Media;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL Fs;
EFI_FILE_SYSTEM_INFO FsInfo;
CHAR16 Label[20];
BOOTMON_FS_FILE *RootFile; // All the other files are linked to this root
BOOLEAN Initialized;
};
#define BOOTMON_FS_SIGNATURE SIGNATURE_32('b', 'o', 't', 'm')
#define BOOTMON_FS_FROM_FS_THIS(a) CR (a, BOOTMON_FS_INSTANCE, Fs, BOOTMON_FS_SIGNATURE)
#define BOOTMON_FS_FROM_LINK(a) CR (a, BOOTMON_FS_INSTANCE, Link, BOOTMON_FS_SIGNATURE)
#include "BootMonFsApi.h"
#endif

View File

@ -0,0 +1,628 @@
/** @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 "BootMonFsInternal.h"
// Clear a file's image description on storage media:
// UEFI allows you to seek past the end of a file, a subsequent write will grow
// the file. It does not specify how space between the former end of the file
// and the beginning of the write should be filled. It's therefore possible that
// BootMonFs metadata, that comes after the end of a file, could be left there
// and wrongly detected by BootMonFsImageInBlock.
STATIC
EFI_STATUS
InvalidateImageDescription (
IN BOOTMON_FS_FILE *File
)
{
EFI_DISK_IO_PROTOCOL *DiskIo;
EFI_BLOCK_IO_PROTOCOL *BlockIo;
UINT32 MediaId;
UINT32 BlockSize;
VOID *Buffer;
EFI_STATUS Status;
UINT64 DescriptionAddress;
DiskIo = File->Instance->DiskIo;
BlockIo = File->Instance->BlockIo;
MediaId = BlockIo->Media->MediaId;
BlockSize = BlockIo->Media->BlockSize;
DescriptionAddress = (File->HwDescription.BlockEnd * BlockSize)
- sizeof (HW_IMAGE_DESCRIPTION);
Buffer = AllocateZeroPool (sizeof (HW_IMAGE_DESCRIPTION));
Status = DiskIo->WriteDisk (DiskIo,
MediaId,
DescriptionAddress,
sizeof (HW_IMAGE_DESCRIPTION),
Buffer
);
FreePool(Buffer);
return Status;
}
// Flush file data that will extend the file's length. Update and, if necessary,
// move the image description.
// We need to pass the file's starting position on media (FileStart), because
// if the file hasn't been flushed before its Description->BlockStart won't
// have been initialised.
// FileStart must be aligned to the media's block size.
// Note that this function uses DiskIo to flush, so call BlockIo->FlushBlocks()
// after calling it.
STATIC
EFI_STATUS
FlushAppendRegion (
IN BOOTMON_FS_FILE *File,
IN BOOTMON_FS_FILE_REGION *Region,
IN UINT64 NewFileSize,
IN UINT64 FileStart
)
{
EFI_STATUS Status;
EFI_DISK_IO_PROTOCOL *DiskIo;
UINTN BlockSize;
HW_IMAGE_DESCRIPTION *Description;
DiskIo = File->Instance->DiskIo;
BlockSize = File->Instance->BlockIo->Media->BlockSize;
ASSERT (FileStart % BlockSize == 0);
// Only invalidate the Image Description of files that have already been
// written in Flash
if (File->HwDescription.RegionCount > 0) {
Status = InvalidateImageDescription (File);
ASSERT_EFI_ERROR (Status);
}
//
// Update File Description
//
Description = &File->HwDescription;
Description->Attributes = 1;
Description->BlockStart = FileStart / BlockSize;
Description->BlockEnd = Description->BlockStart + (NewFileSize / BlockSize);
Description->Footer.FooterSignature1 = HW_IMAGE_FOOTER_SIGNATURE_1;
Description->Footer.FooterSignature2 = HW_IMAGE_FOOTER_SIGNATURE_2;
Description->Footer.Version = HW_IMAGE_FOOTER_VERSION;
Description->Footer.Offset = HW_IMAGE_FOOTER_OFFSET;
Description->RegionCount = 1;
Description->Region[0].Checksum = 0;
Description->Region[0].Offset = Description->BlockStart * BlockSize;
Description->Region[0].Size = NewFileSize - sizeof (HW_IMAGE_DESCRIPTION);
Status = BootMonFsComputeFooterChecksum (Description);
if (EFI_ERROR (Status)) {
return Status;
}
// Write the new file data
Status = DiskIo->WriteDisk (
DiskIo,
File->Instance->Media->MediaId,
FileStart + Region->Offset,
Region->Size,
Region->Buffer
);
ASSERT_EFI_ERROR (Status);
// Round the file size up to the nearest block size
if ((NewFileSize % BlockSize) > 0) {
NewFileSize += BlockSize - (NewFileSize % BlockSize);
}
// Update the file description on the media
Status = DiskIo->WriteDisk (
DiskIo,
File->Instance->Media->MediaId,
(FileStart + NewFileSize) - sizeof (HW_IMAGE_DESCRIPTION),
sizeof (HW_IMAGE_DESCRIPTION),
Description
);
ASSERT_EFI_ERROR (Status);
return Status;
}
BOOLEAN
BootMonFsFileNeedFlush (
IN BOOTMON_FS_FILE *File
)
{
return !IsListEmpty (&File->RegionToFlushLink);
}
// Find a space on media for a file that has not yet been flushed to disk.
// Just returns the first space that's big enough.
// This function could easily be adapted to:
// - Find space for moving an existing file that has outgrown its space
// (We do not currently move files, just return EFI_VOLUME_FULL)
// - Find space for a fragment of a file that has outgrown its space
// (We do not currently fragment files - it's not clear whether fragmentation
// is actually part of BootMonFs as there is no spec)
// - Be more clever about finding space (choosing the largest or smallest
// suitable space)
// Parameters:
// File - the new (not yet flushed) file for which we need to find space.
// FileStart - the position on media of the file (in bytes).
STATIC
EFI_STATUS
BootMonFsFindSpaceForNewFile (
IN BOOTMON_FS_FILE *File,
OUT UINT64 *FileStart
)
{
LIST_ENTRY *FileLink;
BOOTMON_FS_FILE *RootFile;
BOOTMON_FS_FILE *FileEntry;
UINTN BlockSize;
UINT64 FileSize;
EFI_BLOCK_IO_MEDIA *Media;
Media = File->Instance->BlockIo->Media;
BlockSize = Media->BlockSize;
RootFile = File->Instance->RootFile;
if (IsListEmpty (&RootFile->Link)) {
return EFI_SUCCESS;
}
// This function must only be called for file which has not been flushed into
// Flash yet
ASSERT (File->HwDescription.RegionCount == 0);
// Find out how big the file will be
FileSize = BootMonFsGetImageLength (File);
// Add the file header to the file
FileSize += sizeof (HW_IMAGE_DESCRIPTION);
*FileStart = 0;
// Go through all the files in the list
for (FileLink = GetFirstNode (&RootFile->Link);
!IsNull (&RootFile->Link, FileLink);
FileLink = GetNextNode (&RootFile->Link, FileLink)
)
{
FileEntry = BOOTMON_FS_FILE_FROM_LINK_THIS (FileLink);
// If the free space preceding the file is big enough to contain the new
// file then use it!
if (((FileEntry->HwDescription.BlockStart * BlockSize) - *FileStart)
>= FileSize) {
// The file list must be in disk-order
RemoveEntryList (&File->Link);
File->Link.BackLink = FileLink->BackLink;
File->Link.ForwardLink = FileLink;
FileLink->BackLink->ForwardLink = &File->Link;
FileLink->BackLink = &File->Link;
return EFI_SUCCESS;
} else {
*FileStart = (FileEntry->HwDescription.BlockEnd + 1) * BlockSize;
}
}
// See if there's space after the last file
if ((((Media->LastBlock + 1) * BlockSize) - *FileStart) >= FileSize) {
return EFI_SUCCESS;
} else {
return EFI_VOLUME_FULL;
}
}
// Free the resources in the file's Region list.
STATIC
VOID
FreeFileRegions (
IN BOOTMON_FS_FILE *File
)
{
LIST_ENTRY *RegionToFlushLink;
BOOTMON_FS_FILE_REGION *Region;
RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);
while (!IsNull (&File->RegionToFlushLink, RegionToFlushLink)) {
// Repeatedly remove the first node from the list and free its resources.
Region = (BOOTMON_FS_FILE_REGION *) RegionToFlushLink;
RemoveEntryList (RegionToFlushLink);
FreePool (Region->Buffer);
FreePool (Region);
RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);
}
}
EFIAPI
EFI_STATUS
BootMonFsFlushFile (
IN EFI_FILE_PROTOCOL *This
)
{
EFI_STATUS Status;
BOOTMON_FS_INSTANCE *Instance;
LIST_ENTRY *RegionToFlushLink;
BOOTMON_FS_FILE *File;
BOOTMON_FS_FILE *NextFile;
BOOTMON_FS_FILE_REGION *Region;
LIST_ENTRY *FileLink;
UINTN CurrentPhysicalSize;
UINTN BlockSize;
UINT64 FileStart;
UINT64 FileEnd;
UINT64 RegionStart;
UINT64 RegionEnd;
UINT64 NewFileSize;
UINT64 EndOfAppendSpace;
BOOLEAN HasSpace;
EFI_DISK_IO_PROTOCOL *DiskIo;
EFI_BLOCK_IO_PROTOCOL *BlockIo;
Status = EFI_SUCCESS;
FileStart = 0;
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
if (File == NULL) {
return EFI_INVALID_PARAMETER;
}
// Check if the file needs to be flushed
if (!BootMonFsFileNeedFlush (File)) {
return Status;
}
Instance = File->Instance;
BlockIo = Instance->BlockIo;
DiskIo = Instance->DiskIo;
BlockSize = BlockIo->Media->BlockSize;
// If the file doesn't exist then find a space for it
if (File->HwDescription.RegionCount == 0) {
Status = BootMonFsFindSpaceForNewFile (File, &FileStart);
// FileStart has changed so we need to recompute RegionEnd
if (EFI_ERROR (Status)) {
return Status;
}
} else {
FileStart = File->HwDescription.BlockStart * BlockSize;
}
// FileEnd is the NOR address of the end of the file's data
FileEnd = FileStart + BootMonFsGetImageLength (File);
for (RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);
!IsNull (&File->RegionToFlushLink, RegionToFlushLink);
RegionToFlushLink = GetNextNode (&File->RegionToFlushLink, RegionToFlushLink)
)
{
Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink;
// RegionStart and RegionEnd are the the intended NOR address of the
// start and end of the region
RegionStart = FileStart + Region->Offset;
RegionEnd = RegionStart + Region->Size;
if (RegionEnd < FileEnd) {
// Handle regions representing edits to existing portions of the file
// Write the region data straight into the file
Status = DiskIo->WriteDisk (DiskIo,
BlockIo->Media->MediaId,
RegionStart,
Region->Size,
Region->Buffer
);
if (EFI_ERROR (Status)) {
return Status;
}
} else {
// Handle regions representing appends to the file
//
// Note: Since seeking past the end of the file with SetPosition() is
// valid, it's possible there will be a gap between the current end of
// the file and the beginning of the new region. Since the UEFI spec
// says nothing about this case (except "a subsequent write would grow
// the file"), we just leave garbage in the gap.
// Check if there is space to append the new region
HasSpace = FALSE;
NewFileSize = (RegionEnd - FileStart) + sizeof (HW_IMAGE_DESCRIPTION);
CurrentPhysicalSize = BootMonFsGetPhysicalSize (File);
if (NewFileSize <= CurrentPhysicalSize) {
HasSpace = TRUE;
} else {
// Get the File Description for the next file
FileLink = GetNextNode (&Instance->RootFile->Link, &File->Link);
if (!IsNull (&Instance->RootFile->Link, FileLink)) {
NextFile = BOOTMON_FS_FILE_FROM_LINK_THIS (FileLink);
// If there is space between the beginning of the current file and the
// beginning of the next file then use it
EndOfAppendSpace = NextFile->HwDescription.BlockStart * BlockSize;
} else {
// We are flushing the last file.
EndOfAppendSpace = (BlockIo->Media->LastBlock + 1) * BlockSize;
}
if (EndOfAppendSpace - FileStart >= NewFileSize) {
HasSpace = TRUE;
}
}
if (HasSpace == TRUE) {
Status = FlushAppendRegion (File, Region, NewFileSize, FileStart);
if (EFI_ERROR (Status)) {
return Status;
}
} else {
// There isn't a space for the file.
// Options here are to move the file or fragment it. However as files
// may represent boot images at fixed positions, these options will
// break booting if the bootloader doesn't use BootMonFs to find the
// image.
return EFI_VOLUME_FULL;
}
}
}
FreeFileRegions (File);
// Flush DiskIo Buffers (see UEFI Spec 12.7 - DiskIo buffers are flushed by
// calling FlushBlocks on the same device's BlockIo).
BlockIo->FlushBlocks (BlockIo);
return Status;
}
/**
Closes a file on the Nor Flash FS volume.
@param This The EFI_FILE_PROTOCOL to close.
@return Always returns EFI_SUCCESS.
**/
EFIAPI
EFI_STATUS
BootMonFsCloseFile (
IN EFI_FILE_PROTOCOL *This
)
{
// Flush the file if needed
This->Flush (This);
return EFI_SUCCESS;
}
// Create a new instance of BOOTMON_FS_FILE.
// Uses BootMonFsCreateFile to
STATIC
EFI_STATUS
CreateNewFile (
IN BOOTMON_FS_INSTANCE *Instance,
IN CHAR8* AsciiFileName,
OUT BOOTMON_FS_FILE **NewHandle
)
{
EFI_STATUS Status;
BOOTMON_FS_FILE *File;
Status = BootMonFsCreateFile (Instance, &File);
if (EFI_ERROR (Status)) {
return Status;
}
// Remove the leading '\\'
if (*AsciiFileName == '\\') {
AsciiFileName++;
}
// Set the file name
CopyMem (File->HwDescription.Footer.Filename, AsciiFileName, MAX_NAME_LENGTH);
// Add the file to list of files of the File System
InsertHeadList (&Instance->RootFile->Link, &File->Link);
*NewHandle = File;
return Status;
}
/**
Opens a file on the Nor Flash FS volume
Calls BootMonFsGetFileFromAsciiFilename to search the list of tracked files.
@param This The EFI_FILE_PROTOCOL parent handle.
@param NewHandle Double-pointer to the newly created protocol.
@param FileName The name of the image/metadata on flash
@param OpenMode Read,write,append etc
@param Attributes ?
@return EFI_STATUS
OUT_OF_RESOURCES
Run out of space to keep track of the allocated structures
DEVICE_ERROR
Unable to locate the volume associated with the parent file handle
NOT_FOUND
Filename wasn't found on flash
SUCCESS
**/
EFIAPI
EFI_STATUS
BootMonFsOpenFile (
IN EFI_FILE_PROTOCOL *This,
OUT EFI_FILE_PROTOCOL **NewHandle,
IN CHAR16 *FileName,
IN UINT64 OpenMode,
IN UINT64 Attributes
)
{
BOOTMON_FS_FILE *Directory;
BOOTMON_FS_FILE *File;
BOOTMON_FS_INSTANCE *Instance;
CHAR8* AsciiFileName;
EFI_STATUS Status;
if ((FileName == NULL) || (NewHandle == NULL)) {
return EFI_INVALID_PARAMETER;
}
// The only valid modes are read, read/write, and read/write/create
if (!(OpenMode & EFI_FILE_MODE_READ) || ((OpenMode & EFI_FILE_MODE_CREATE) && !(OpenMode & EFI_FILE_MODE_WRITE))) {
return EFI_INVALID_PARAMETER;
}
Directory = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
if (Directory == NULL) {
return EFI_DEVICE_ERROR;
}
Instance = Directory->Instance;
// If the instance has not been initialized it yet then do it ...
if (!Instance->Initialized) {
Status = BootMonFsInitialize (Instance);
if (EFI_ERROR (Status)) {
return Status;
}
}
// BootMonFs interface requires ASCII filenames
AsciiFileName = AllocatePool ((StrLen (FileName) + 1) * sizeof (CHAR8));
if (AsciiFileName == NULL) {
return EFI_OUT_OF_RESOURCES;
}
UnicodeStrToAsciiStr (FileName, AsciiFileName);
if ((AsciiStrCmp (AsciiFileName, "\\") == 0) ||
(AsciiStrCmp (AsciiFileName, "/") == 0) ||
(AsciiStrCmp (AsciiFileName, "") == 0) ||
(AsciiStrCmp (AsciiFileName, ".") == 0))
{
//
// Opening '/', '\', '.', or the NULL pathname is trying to open the root directory
//
*NewHandle = &Instance->RootFile->File;
Instance->RootFile->Position = 0;
Status = EFI_SUCCESS;
} else {
//
// Open or Create a regular file
//
// Check if the file already exists
Status = BootMonGetFileFromAsciiFileName (Instance, AsciiFileName, &File);
if (Status == EFI_NOT_FOUND) {
// The file doesn't exist.
if (OpenMode & EFI_FILE_MODE_CREATE) {
// If the file does not exist but is required then create it.
if (Attributes & EFI_FILE_DIRECTORY) {
// BootMonFS doesn't support subdirectories
Status = EFI_UNSUPPORTED;
} else {
// Create a new file
Status = CreateNewFile (Instance, AsciiFileName, &File);
if (!EFI_ERROR (Status)) {
File->OpenMode = OpenMode;
*NewHandle = &File->File;
File->Position = 0;
}
}
}
} else if (Status == EFI_SUCCESS) {
// The file exists
File->OpenMode = OpenMode;
*NewHandle = &File->File;
File->Position = 0;
}
}
FreePool (AsciiFileName);
return Status;
}
// Delete() for the root directory's EFI_FILE_PROTOCOL instance
EFIAPI
EFI_STATUS
BootMonFsDeleteFail (
IN EFI_FILE_PROTOCOL *This
)
{
This->Close(This);
// You can't delete the root directory
return EFI_WARN_DELETE_FAILURE;
}
EFIAPI
EFI_STATUS
BootMonFsDelete (
IN EFI_FILE_PROTOCOL *This
)
{
EFI_STATUS Status;
BOOTMON_FS_FILE *File;
LIST_ENTRY *RegionToFlushLink;
BOOTMON_FS_FILE_REGION *Region;
HW_IMAGE_DESCRIPTION *Description;
EFI_BLOCK_IO_PROTOCOL *BlockIo;
UINT8 *EmptyBuffer;
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
if (File == NULL) {
return EFI_DEVICE_ERROR;
}
Status = EFI_SUCCESS;
if (BootMonFsFileNeedFlush (File)) {
// Free the entries from the Buffer List
RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);
do {
Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink;
// Get Next entry
RegionToFlushLink = RemoveEntryList (RegionToFlushLink);
// Free the buffers
FreePool (Region->Buffer);
FreePool (Region);
} while (!IsListEmpty (&File->RegionToFlushLink));
}
// If (RegionCount is greater than 0) then the file already exists
if (File->HwDescription.RegionCount > 0) {
Description = &File->HwDescription;
BlockIo = File->Instance->BlockIo;
// Create an empty buffer
EmptyBuffer = AllocateZeroPool (BlockIo->Media->BlockSize);
if (EmptyBuffer == NULL) {
FreePool (File);
return EFI_OUT_OF_RESOURCES;
}
// Invalidate the last Block
Status = BlockIo->WriteBlocks (BlockIo, BlockIo->Media->MediaId, Description->BlockEnd, BlockIo->Media->BlockSize, EmptyBuffer);
ASSERT_EFI_ERROR (Status);
FreePool (EmptyBuffer);
}
// Remove the entry from the list
RemoveEntryList (&File->Link);
FreePool (File);
return Status;
}

View File

@ -0,0 +1,163 @@
/** @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 <Protocol/SimpleFileSystem.h>
#include <Library/UefiLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/DebugLib.h>
#include "BootMonFsInternal.h"
EFIAPI
EFI_STATUS
BootMonFsReadFile (
IN EFI_FILE_PROTOCOL *This,
IN OUT UINTN *BufferSize,
OUT VOID *Buffer
)
{
BOOTMON_FS_INSTANCE *Instance;
BOOTMON_FS_FILE *File;
EFI_DISK_IO_PROTOCOL *DiskIo;
EFI_BLOCK_IO_MEDIA *Media;
UINT64 FileStart;
EFI_STATUS Status;
UINTN RemainingFileSize;
// Ensure the file has been written in Flash before reading it.
// This keeps the code simple and avoids having to manage a non-flushed file.
BootMonFsFlushFile (This);
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
if (File == NULL) {
return EFI_INVALID_PARAMETER;
}
Instance = File->Instance;
DiskIo = Instance->DiskIo;
Media = Instance->Media;
FileStart = (Media->LowestAlignedLba + File->HwDescription.BlockStart) * Media->BlockSize;
if (File->Position >= File->HwDescription.Region[0].Size) {
// The entire file has been read
*BufferSize = 0;
return EFI_DEVICE_ERROR;
}
// This driver assumes that the entire file is in region 0.
RemainingFileSize = File->HwDescription.Region[0].Size - File->Position;
// If read would go past end of file, truncate the read
if (*BufferSize > RemainingFileSize) {
*BufferSize = RemainingFileSize;
}
Status = DiskIo->ReadDisk (
DiskIo,
Media->MediaId,
FileStart + File->Position,
*BufferSize,
Buffer
);
if (EFI_ERROR (Status)) {
*BufferSize = 0;
}
File->Position += *BufferSize;
return Status;
}
// Inserts an entry into the write chain
EFIAPI
EFI_STATUS
BootMonFsWriteFile (
IN EFI_FILE_PROTOCOL *This,
IN OUT UINTN *BufferSize,
IN VOID *Buffer
)
{
BOOTMON_FS_FILE *File;
BOOTMON_FS_FILE_REGION *Region;
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
if (File == NULL) {
return EFI_INVALID_PARAMETER;
}
if (!(File->OpenMode & EFI_FILE_MODE_WRITE)) {
return EFI_ACCESS_DENIED;
}
// Allocate and initialize the memory region
Region = (BOOTMON_FS_FILE_REGION*)AllocateZeroPool (sizeof (BOOTMON_FS_FILE_REGION));
if (Region == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Region->Buffer = AllocateCopyPool (*BufferSize, Buffer);
if (Region->Buffer == NULL) {
FreePool (Region);
return EFI_OUT_OF_RESOURCES;
}
Region->Size = *BufferSize;
Region->Offset = File->Position;
InsertTailList (&File->RegionToFlushLink, &Region->Link);
File->Position += *BufferSize;
return EFI_SUCCESS;
}
EFIAPI
EFI_STATUS
BootMonFsSetPosition (
IN EFI_FILE_PROTOCOL *This,
IN UINT64 Position
)
{
BOOTMON_FS_FILE *File;
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
// UEFI Spec section 12.5:
// "Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to
// be set to the end of the file."
if (Position == 0xFFFFFFFFFFFFFFFF) {
File->Position = BootMonFsGetImageLength (File);
} else {
// NB: Seeking past the end of the file is valid.
File->Position = Position;
}
return EFI_SUCCESS;
}
EFIAPI
EFI_STATUS
BootMonFsGetPosition (
IN EFI_FILE_PROTOCOL *This,
OUT UINT64 *Position
) {
BOOTMON_FS_FILE *File;
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
*Position = File->Position;
return EFI_SUCCESS;
}

View File

@ -0,0 +1,37 @@
/** @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 "BootMonFsInternal.h"
EFIAPI
EFI_STATUS
BootMonFsSetPositionUnsupported (
IN EFI_FILE_PROTOCOL *This,
IN UINT64 Position
)
{
ASSERT(0);
return EFI_UNSUPPORTED;
}
EFIAPI
EFI_STATUS
BootMonFsGetPositionUnsupported (
IN EFI_FILE_PROTOCOL *This,
OUT UINT64 *Position
)
{
ASSERT(0);
return EFI_UNSUPPORTED;
}