summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ArmPlatformPkg/ArmPlatformPkg.dec5
-rw-r--r--ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15-A7.fdf6
-rw-r--r--ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA9x4.fdf6
-rw-r--r--ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15.fdf6
-rw-r--r--ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15_MPCore.fdf6
-rw-r--r--ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A9x4.fdf7
-rw-r--r--ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc12
-rw-r--r--ArmPlatformPkg/FileSystem/BootMonFs/BootMonFs.inf59
-rw-r--r--ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsApi.h216
-rw-r--r--ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsDir.c602
-rw-r--r--ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsEntryPoint.c479
-rw-r--r--ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsHw.h53
-rw-r--r--ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsImages.c214
-rw-r--r--ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsInternal.h93
-rw-r--r--ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsOpenClose.c628
-rw-r--r--ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsReadWrite.c163
-rw-r--r--ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsUnsupported.c37
17 files changed, 2582 insertions, 10 deletions
diff --git a/ArmPlatformPkg/ArmPlatformPkg.dec b/ArmPlatformPkg/ArmPlatformPkg.dec
index b459db21b2..114c5916c3 100644
--- a/ArmPlatformPkg/ArmPlatformPkg.dec
+++ b/ArmPlatformPkg/ArmPlatformPkg.dec
@@ -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
#
diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15-A7.fdf b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15-A7.fdf
index 465b88a800..3454e2bcd1 100644
--- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15-A7.fdf
+++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15-A7.fdf
@@ -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
#
diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA9x4.fdf b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA9x4.fdf
index cd44c51645..1b316c7ab5 100644
--- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA9x4.fdf
+++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA9x4.fdf
@@ -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
#
diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15.fdf b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15.fdf
index 133b2d5ecc..c9162f2417 100644
--- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15.fdf
+++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15.fdf
@@ -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
#
diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15_MPCore.fdf b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15_MPCore.fdf
index a3feee7003..ec20e33cd1 100644
--- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15_MPCore.fdf
+++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15_MPCore.fdf
@@ -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
#
diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A9x4.fdf b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A9x4.fdf
index f278355f9a..f4ae329ae8 100644
--- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A9x4.fdf
+++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A9x4.fdf
@@ -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
@@ -149,6 +149,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
#
INF MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf
diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc
index 7d405379e6..19dd9cc669 100644
--- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc
+++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc
@@ -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
@@ -328,6 +328,13 @@
#
#
+ # FileSystem
+ #
+
+ # List of Device Paths that support BootMonFs
+ gArmPlatformTokenSpaceGuid.PcdBootMonFsSupportedDevicePaths|L"VenHw(1F15DA3C-37FF-4070-B471-BB4AF12A724A)"
+
+ #
# ARM OS Loader
#
# Versatile Express machine type (ARM VERSATILE EXPRESS = 2272) required for ARM Linux:
@@ -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
diff --git a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFs.inf b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFs.inf
new file mode 100644
index 0000000000..d7770f0b96
--- /dev/null
+++ b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFs.inf
@@ -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
+
diff --git a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsApi.h b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsApi.h
new file mode 100644
index 0000000000..4f0122e32b
--- /dev/null
+++ b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsApi.h
@@ -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
diff --git a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsDir.c b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsDir.c
new file mode 100644
index 0000000000..773490e37a
--- /dev/null
+++ b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsDir.c
@@ -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;
+}
diff --git a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsEntryPoint.c b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsEntryPoint.c
new file mode 100644
index 0000000000..00f7c077ea
--- /dev/null
+++ b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsEntryPoint.c
@@ -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;
+}
diff --git a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsHw.h b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsHw.h
new file mode 100644
index 0000000000..3ebb5ba54a
--- /dev/null
+++ b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsHw.h
@@ -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
diff --git a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsImages.c b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsImages.c
new file mode 100644
index 0000000000..7d3e901903
--- /dev/null
+++ b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsImages.c
@@ -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;
+}
diff --git a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsInternal.h b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsInternal.h
new file mode 100644
index 0000000000..8bcbac6433
--- /dev/null
+++ b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsInternal.h
@@ -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
+
diff --git a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsOpenClose.c b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsOpenClose.c
new file mode 100644
index 0000000000..908393fa53
--- /dev/null
+++ b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsOpenClose.c
@@ -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;
+}
+
diff --git a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsReadWrite.c b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsReadWrite.c
new file mode 100644
index 0000000000..653b2c507c
--- /dev/null
+++ b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsReadWrite.c
@@ -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;
+}
diff --git a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsUnsupported.c b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsUnsupported.c
new file mode 100644
index 0000000000..4ecc4ea008
--- /dev/null
+++ b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsUnsupported.c
@@ -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;
+}