]> git.proxmox.com Git - mirror_edk2.git/commitdiff
ArmPlatformPkg/BootMonFs: Added support for the NorFlash File System of the ARM Devel...
authorOlivier Martin <olivier.martin@arm.com>
Thu, 16 Jan 2014 00:06:13 +0000 (00:06 +0000)
committeroliviermartin <oliviermartin@6f19259b-4bc3-4df7-8a09-765794883524>
Thu, 16 Jan 2014 00:06:13 +0000 (00:06 +0000)
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

17 files changed:
ArmPlatformPkg/ArmPlatformPkg.dec
ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15-A7.fdf
ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA9x4.fdf
ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15.fdf
ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15_MPCore.fdf
ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A9x4.fdf
ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc
ArmPlatformPkg/FileSystem/BootMonFs/BootMonFs.inf [new file with mode: 0644]
ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsApi.h [new file with mode: 0644]
ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsDir.c [new file with mode: 0644]
ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsEntryPoint.c [new file with mode: 0644]
ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsHw.h [new file with mode: 0644]
ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsImages.c [new file with mode: 0644]
ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsInternal.h [new file with mode: 0644]
ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsOpenClose.c [new file with mode: 0644]
ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsReadWrite.c [new file with mode: 0644]
ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsUnsupported.c [new file with mode: 0644]

index b459db21b2a231711060db5d699e35027e85fd60..114c5916c381c63674d8ee7dafb2d8dd1a029f06 100644 (file)
@@ -1,6 +1,6 @@
 #/** @file\r
 #\r
-#  Copyright (c) 2011-2013, ARM Limited. All rights reserved.\r
+#  Copyright (c) 2011-2014, ARM Limited. All rights reserved.\r
 #  \r
 #  This program and the accompanying materials                          \r
 #  are licensed and made available under the terms and conditions of the BSD License         \r
@@ -86,6 +86,9 @@
   # Size to reserve in the primary core stack for SEC Global Variables\r
   gArmPlatformTokenSpaceGuid.PcdSecGlobalVariableSize|0x0|UINT32|0x00000031\r
 \r
+  # Boot Monitor FileSystem\r
+  gArmPlatformTokenSpaceGuid.PcdBootMonFsSupportedDevicePaths|L""|VOID*|0x0000003A\r
+\r
   #\r
   # ARM Primecells\r
   #\r
index 465b88a8002f92a2bec278ca253e7b170aa72cf2..3454e2bcd182eeaf52e10803a09e1cd79392adee 100644 (file)
@@ -1,5 +1,5 @@
 #\r
-#  Copyright (c) 2012, ARM Limited. All rights reserved.\r
+#  Copyright (c) 2012-2014, ARM Limited. All rights reserved.\r
 #  \r
 #  This program and the accompanying materials                          \r
 #  are licensed and made available under the terms and conditions of the BSD License         \r
@@ -120,6 +120,10 @@ READ_LOCK_STATUS   = TRUE
   INF FatBinPkg/EnhancedFatDxe/Fat.inf\r
   INF MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf\r
 \r
+  # Versatile Express FileSystem\r
+  INF ArmPlatformPkg/FileSystem/BootMonFs/BootMonFs.inf\r
+\r
+  # ACPI Support\r
   INF MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf\r
   \r
   #\r
index cd44c516454fb043d28ef42a49e1b7e0e6305b8e..1b316c7ab5bfa68cb0c36baf9f7223e50eac4384 100644 (file)
@@ -1,6 +1,5 @@
-# FLASH layout file for ARM VE.\r
 #\r
-#  Copyright (c) 2011, ARM Limited. All rights reserved.\r
+#  Copyright (c) 2011-2014, ARM Limited. All rights reserved.\r
 #  \r
 #  This program and the accompanying materials                          \r
 #  are licensed and made available under the terms and conditions of the BSD License         \r
@@ -189,6 +188,9 @@ READ_LOCK_STATUS   = TRUE
   INF FatBinPkg/EnhancedFatDxe/Fat.inf\r
   INF MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf\r
 \r
+  # Versatile Express FileSystem\r
+  INF ArmPlatformPkg/FileSystem/BootMonFs/BootMonFs.inf\r
+\r
   #\r
   # Multimedia Card Interface\r
   #\r
index 133b2d5eccfe892f550419aff5d14cd432502f47..c9162f2417f6824473b9972d317b313e6e962283 100644 (file)
@@ -1,6 +1,5 @@
-# FLASH layout file for ARM VE.\r
 #\r
-#  Copyright (c) 2011, ARM Limited. All rights reserved.\r
+#  Copyright (c) 2011-2014, ARM Limited. All rights reserved.\r
 #  \r
 #  This program and the accompanying materials                          \r
 #  are licensed and made available under the terms and conditions of the BSD License         \r
@@ -157,6 +156,9 @@ READ_LOCK_STATUS   = TRUE
   INF FatBinPkg/EnhancedFatDxe/Fat.inf\r
   INF MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf\r
 \r
+  # Versatile Express FileSystem\r
+  INF ArmPlatformPkg/FileSystem/BootMonFs/BootMonFs.inf\r
+\r
   #\r
   # Multimedia Card Interface\r
   #\r
index a3feee700386cdce7ce5555316f208608ce0f327..ec20e33cd110716d84db21cff2724e7dd4b0aa1d 100644 (file)
@@ -1,6 +1,5 @@
-# FLASH layout file for ARM VE.\r
 #\r
-#  Copyright (c) 2011, ARM Limited. All rights reserved.\r
+#  Copyright (c) 2011-2014, ARM Limited. All rights reserved.\r
 #  \r
 #  This program and the accompanying materials                          \r
 #  are licensed and made available under the terms and conditions of the BSD License         \r
@@ -157,6 +156,9 @@ READ_LOCK_STATUS   = TRUE
   INF FatBinPkg/EnhancedFatDxe/Fat.inf\r
   INF MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf\r
 \r
+  # Versatile Express FileSystem\r
+  INF ArmPlatformPkg/FileSystem/BootMonFs/BootMonFs.inf\r
+\r
   #\r
   # Multimedia Card Interface\r
   #\r
index f278355f9a3cd69db6abbddca35e5adba1563651..f4ae329ae8ccd2140304ac2980e0c6920b64843a 100644 (file)
@@ -1,5 +1,5 @@
 #\r
-#  Copyright (c) 2011, ARM Limited. All rights reserved.\r
+#  Copyright (c) 2011-2014, ARM Limited. All rights reserved.\r
 #  \r
 #  This program and the accompanying materials                          \r
 #  are licensed and made available under the terms and conditions of the BSD License         \r
@@ -148,6 +148,11 @@ READ_LOCK_STATUS   = TRUE
   #\r
   INF ArmPkg/Filesystem/SemihostFs/SemihostFs.inf\r
   \r
+  #\r
+  # Versatile Express FileSystem\r
+  #\r
+  INF ArmPlatformPkg/FileSystem/BootMonFs/BootMonFs.inf\r
+\r
   #\r
   # FAT filesystem + GPT/MBR partitioning\r
   #\r
index 7d405379e60485af79e3ecf713607cf904eec16c..19dd9cc66902fac5c5733173ec1283641a3f5a24 100644 (file)
@@ -1,5 +1,5 @@
 #\r
-#  Copyright (c) 2011-2012, ARM Limited. All rights reserved.\r
+#  Copyright (c) 2011-2014, ARM Limited. All rights reserved.\r
 #  \r
 #  This program and the accompanying materials                          \r
 #  are licensed and made available under the terms and conditions of the BSD License         \r
   # ARM PrimeCell\r
   #\r
 \r
+  #\r
+  # FileSystem\r
+  #\r
+\r
+  # List of Device Paths that support BootMonFs\r
+  gArmPlatformTokenSpaceGuid.PcdBootMonFsSupportedDevicePaths|L"VenHw(1F15DA3C-37FF-4070-B471-BB4AF12A724A)"\r
+\r
   #\r
   # ARM OS Loader\r
   #\r
   gArmPlatformTokenSpaceGuid.PcdDefaultConInPaths|L"VenHw(D3987D4B-971A-435F-8CAF-4967EB627241)/Uart(38400,8,N,1)/VenPcAnsi()"\r
   gArmPlatformTokenSpaceGuid.PcdPlatformBootTimeOut|10\r
 \r
+[Components.common]\r
+  # Versatile Express FileSystem\r
+  ArmPlatformPkg/FileSystem/BootMonFs/BootMonFs.inf\r
diff --git a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFs.inf b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFs.inf
new file mode 100644 (file)
index 0000000..d7770f0
--- /dev/null
@@ -0,0 +1,59 @@
+#/** @file\r
+#  Support for ARM Boot Monitor File System\r
+#\r
+#  Copyright (c) 2012-2014, ARM Ltd. All rights reserved.<BR>\r
+#\r
+#  This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution.  The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\r
+#\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#**/\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = BootMonFs\r
+  FILE_GUID                      = 7abbc454-f737-4322-931c-b1bb62a01d6f\r
+  MODULE_TYPE                    = UEFI_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+\r
+  ENTRY_POINT                    = BootMonFsEntryPoint\r
+\r
+[Sources]\r
+  BootMonFsEntryPoint.c\r
+  BootMonFsOpenClose.c\r
+  BootMonFsDir.c\r
+  BootMonFsImages.c\r
+  BootMonFsReadWrite.c\r
+  BootMonFsUnsupported.c\r
+\r
+[Packages]\r
+  ArmPlatformPkg/ArmPlatformPkg.dec\r
+  MdePkg/MdePkg.dec\r
+\r
+[LibraryClasses]\r
+  BaseLib\r
+  DevicePathLib\r
+  MemoryAllocationLib\r
+  PrintLib\r
+  UefiDriverEntryPoint\r
+  UefiLib\r
+\r
+[Guids]\r
+  gEfiFileSystemInfoGuid\r
+  gEfiFileInfoGuid\r
+  gEfiFileSystemVolumeLabelInfoIdGuid\r
+\r
+[Pcd]\r
+  gArmPlatformTokenSpaceGuid.PcdBootMonFsSupportedDevicePaths\r
+\r
+[Protocols]\r
+  gEfiDiskIoProtocolGuid\r
+  gEfiBlockIoProtocolGuid\r
+  gEfiSimpleFileSystemProtocolGuid\r
+  gEfiDevicePathProtocolGuid\r
+  gEfiDevicePathFromTextProtocolGuid\r
+\r
diff --git a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsApi.h b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsApi.h
new file mode 100644 (file)
index 0000000..4f0122e
--- /dev/null
@@ -0,0 +1,216 @@
+/** @file\r
+*\r
+*  Copyright (c) 2012-2014, ARM Limited. All rights reserved.\r
+*\r
+*  This program and the accompanying materials\r
+*  are licensed and made available under the terms and conditions of the BSD License\r
+*  which accompanies this distribution.  The full text of the license may be found at\r
+*  http://opensource.org/licenses/bsd-license.php\r
+*\r
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+*\r
+**/\r
+\r
+#ifndef __BOOTMON_FS_API_H\r
+#define __BOOTMON_FS_API_H\r
+\r
+#include <Protocol/SimpleFileSystem.h>\r
+\r
+EFI_STATUS\r
+BootMonFsDiscoverNextImage (\r
+  IN BOOTMON_FS_INSTANCE      *Flash,\r
+  IN EFI_LBA                  *LbaStart,\r
+  OUT HW_IMAGE_DESCRIPTION    *Image\r
+  );\r
+\r
+EFI_STATUS\r
+BootMonFsInitialize (\r
+  IN BOOTMON_FS_INSTANCE *Instance\r
+  );\r
+\r
+UINT32\r
+BootMonFsChecksum (\r
+  IN VOID   *Data,\r
+  IN UINT32 Size\r
+  );\r
+\r
+EFI_STATUS\r
+BootMonFsComputeFooterChecksum (\r
+  IN OUT HW_IMAGE_DESCRIPTION *Footer\r
+  );\r
+\r
+EFIAPI\r
+EFI_STATUS\r
+OpenBootMonFsOpenVolume (\r
+  IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,\r
+  OUT EFI_FILE_PROTOCOL              **Root\r
+  );\r
+\r
+UINT32\r
+BootMonFsGetImageLength (\r
+  IN BOOTMON_FS_FILE      *File\r
+  );\r
+\r
+UINTN\r
+BootMonFsGetPhysicalSize (\r
+  IN BOOTMON_FS_FILE* File\r
+  );\r
+\r
+EFI_STATUS\r
+BootMonFsCreateFile (\r
+  IN  BOOTMON_FS_INSTANCE *Instance,\r
+  OUT BOOTMON_FS_FILE     **File\r
+  );\r
+\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsGetInfo (\r
+  IN EFI_FILE_PROTOCOL  *This,\r
+  IN EFI_GUID           *InformationType,\r
+  IN OUT UINTN          *BufferSize,\r
+  OUT VOID              *Buffer\r
+  );\r
+\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsReadDirectory (\r
+  IN EFI_FILE_PROTOCOL    *This,\r
+  IN OUT UINTN            *BufferSize,\r
+  OUT VOID                *Buffer\r
+  );\r
+\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsFlushDirectory (\r
+  IN EFI_FILE_PROTOCOL  *This\r
+  );\r
+\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsFlushFile (\r
+  IN EFI_FILE_PROTOCOL  *This\r
+  );\r
+\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsCloseFile (\r
+  IN EFI_FILE_PROTOCOL  *This\r
+  );\r
+\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsOpenFile (\r
+  IN EFI_FILE_PROTOCOL  *This,\r
+  OUT EFI_FILE_PROTOCOL **NewHandle,\r
+  IN CHAR16             *FileName,\r
+  IN UINT64             OpenMode,\r
+  IN UINT64             Attributes\r
+  );\r
+\r
+\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsReadFile (\r
+  IN EFI_FILE_PROTOCOL  *This,\r
+  IN OUT UINTN          *BufferSize,\r
+  OUT VOID              *Buffer\r
+  );\r
+\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsSetDirPosition (\r
+  IN EFI_FILE_PROTOCOL  *This,\r
+  IN UINT64             Position\r
+  );\r
+\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsGetPosition (\r
+  IN EFI_FILE_PROTOCOL  *This,\r
+  OUT UINT64            *Position\r
+  );\r
+\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsWriteFile (\r
+  IN EFI_FILE_PROTOCOL  *This,\r
+  IN OUT UINTN          *BufferSize,\r
+  IN VOID               *Buffer\r
+  );\r
+\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsDeleteFail (\r
+  IN EFI_FILE_PROTOCOL *This\r
+  );\r
+\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsDelete (\r
+  IN EFI_FILE_PROTOCOL *This\r
+  );\r
+\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsSetPosition (\r
+  IN EFI_FILE_PROTOCOL  *This,\r
+  IN UINT64             Position\r
+  );\r
+\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsGetPosition(\r
+  IN EFI_FILE_PROTOCOL  *This,\r
+  OUT UINT64            *Position\r
+  );\r
+\r
+//\r
+// UNSUPPORTED OPERATIONS\r
+//\r
+\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsGetPositionUnsupported (\r
+  IN EFI_FILE_PROTOCOL  *This,\r
+  OUT UINT64            *Position\r
+  );\r
+\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsSetInfo (\r
+  IN EFI_FILE_PROTOCOL  *This,\r
+  IN EFI_GUID           *InformationType,\r
+  IN UINTN              BufferSize,\r
+  IN VOID               *Buffer\r
+  );\r
+\r
+//\r
+// Directory API\r
+//\r
+\r
+EFI_STATUS\r
+BootMonFsOpenDirectory (\r
+  OUT EFI_FILE_PROTOCOL **NewHandle,\r
+  IN CHAR16             *FileName,\r
+  IN BOOTMON_FS_INSTANCE *Volume\r
+  );\r
+\r
+//\r
+// Internal API\r
+//\r
+EFI_STATUS\r
+BootMonGetFileFromAsciiFileName (\r
+  IN  BOOTMON_FS_INSTANCE   *Instance,\r
+  IN  CHAR8*                AsciiFileName,\r
+  OUT BOOTMON_FS_FILE       **File\r
+  );\r
+\r
+EFI_STATUS\r
+BootMonGetFileFromPosition (\r
+  IN  BOOTMON_FS_INSTANCE   *Instance,\r
+  IN  UINTN                 Position,\r
+  OUT BOOTMON_FS_FILE       **File\r
+  );\r
+\r
+#endif\r
diff --git a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsDir.c b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsDir.c
new file mode 100644 (file)
index 0000000..773490e
--- /dev/null
@@ -0,0 +1,602 @@
+/** @file\r
+*\r
+*  Copyright (c) 2012-2014, ARM Limited. All rights reserved.\r
+*\r
+*  This program and the accompanying materials\r
+*  are licensed and made available under the terms and conditions of the BSD License\r
+*  which accompanies this distribution.  The full text of the license may be found at\r
+*  http://opensource.org/licenses/bsd-license.php\r
+*\r
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+*\r
+**/\r
+\r
+#include "BootMonFsInternal.h"\r
+\r
+EFIAPI\r
+EFI_STATUS\r
+OpenBootMonFsOpenVolume (\r
+  IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,\r
+  OUT EFI_FILE_PROTOCOL              **Root\r
+  )\r
+{\r
+  BOOTMON_FS_INSTANCE *Instance;\r
+\r
+  Instance = BOOTMON_FS_FROM_FS_THIS (This);\r
+  if (Instance == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  *Root = &Instance->RootFile->File;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+UINT32\r
+BootMonFsGetImageLength (\r
+  IN BOOTMON_FS_FILE      *File\r
+  )\r
+{\r
+  UINT32                   Index;\r
+  UINT32                   FileSize;\r
+  LIST_ENTRY              *RegionToFlushLink;\r
+  BOOTMON_FS_FILE_REGION  *Region;\r
+\r
+  FileSize = 0;\r
+\r
+  // Look at all Flash areas to determine file size\r
+  for (Index = 0; Index < HW_IMAGE_DESCRIPTION_REGION_MAX; Index++) {\r
+    FileSize += File->HwDescription.Region[Index].Size;\r
+  }\r
+\r
+  // Add the regions that have not been flushed yet\r
+  for (RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);\r
+       !IsNull (&File->RegionToFlushLink, RegionToFlushLink);\r
+       RegionToFlushLink = GetNextNode (&File->RegionToFlushLink, RegionToFlushLink)\r
+       )\r
+  {\r
+    Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink;\r
+    if (Region->Offset + Region->Size > FileSize) {\r
+      FileSize += Region->Offset + Region->Size;\r
+    }\r
+  }\r
+\r
+  return FileSize;\r
+}\r
+\r
+UINTN\r
+BootMonFsGetPhysicalSize (\r
+  IN BOOTMON_FS_FILE* File\r
+  )\r
+{\r
+  // Return 0 for files that haven't yet been flushed to media\r
+  if (File->HwDescription.RegionCount == 0) {\r
+    return 0;\r
+  }\r
+\r
+  return ((File->HwDescription.BlockEnd - File->HwDescription.BlockStart) + 1 )\r
+          * File->Instance->Media->BlockSize;\r
+}\r
+\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsSetDirPosition (\r
+  IN EFI_FILE_PROTOCOL  *This,\r
+  IN UINT64             Position\r
+  )\r
+{\r
+  BOOTMON_FS_FILE       *File;\r
+\r
+  File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
+  if (File == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  // UEFI Spec section 12.5:\r
+  // "The seek request for nonzero is not valid on open directories."\r
+  if (Position != 0) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  File->Position = Position;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+BootMonFsOpenDirectory (\r
+  OUT EFI_FILE_PROTOCOL **NewHandle,\r
+  IN CHAR16             *FileName,\r
+  IN BOOTMON_FS_INSTANCE *Volume\r
+  )\r
+{\r
+  ASSERT(0);\r
+\r
+  return EFI_UNSUPPORTED;\r
+}\r
+EFI_STATUS\r
+GetFileSystemVolumeLabelInfo (\r
+  IN BOOTMON_FS_INSTANCE *Instance,\r
+  IN OUT UINTN          *BufferSize,\r
+  OUT VOID              *Buffer\r
+  )\r
+{\r
+  UINTN                         Size;\r
+  EFI_FILE_SYSTEM_VOLUME_LABEL *Label;\r
+  EFI_STATUS                    Status;\r
+\r
+  Label = Buffer;\r
+\r
+  // Value returned by StrSize includes null terminator.\r
+  Size = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL\r
+         + StrSize (Instance->FsInfo.VolumeLabel);\r
+\r
+  if (*BufferSize >= Size) {\r
+    CopyMem (&Label->VolumeLabel, &Instance->FsInfo.VolumeLabel, Size);\r
+    Status = EFI_SUCCESS;\r
+  } else {\r
+    Status = EFI_BUFFER_TOO_SMALL;\r
+  }\r
+  *BufferSize = Size;\r
+  return Status;\r
+}\r
+\r
+// Helper function that calculates a rough "free space" by:\r
+// - Taking the media size\r
+// - Subtracting the sum of all file sizes\r
+// - Subtracting the block size times the number of files\r
+//    (To account for the blocks containing the HW_IMAGE_INFO\r
+STATIC\r
+UINT64\r
+ComputeFreeSpace (\r
+  IN BOOTMON_FS_INSTANCE *Instance\r
+  )\r
+{\r
+  LIST_ENTRY   *FileLink;\r
+  UINT64        FileSizeSum;\r
+  UINT64        MediaSize;\r
+  UINTN         NumFiles;\r
+  EFI_BLOCK_IO_MEDIA *Media;\r
+  BOOTMON_FS_FILE *File;\r
+\r
+  Media = Instance->BlockIo->Media;\r
+  MediaSize = Media->BlockSize * (Media->LastBlock + 1);\r
+\r
+  NumFiles = 0;\r
+  FileSizeSum = 0;\r
+  for (FileLink = GetFirstNode (&Instance->RootFile->Link);\r
+         !IsNull (&Instance->RootFile->Link, FileLink);\r
+         FileLink = GetNextNode (&Instance->RootFile->Link, FileLink)\r
+         )\r
+  {\r
+    File = BOOTMON_FS_FILE_FROM_LINK_THIS (FileLink);\r
+    FileSizeSum += BootMonFsGetImageLength (File);\r
+\r
+    NumFiles++;\r
+  }\r
+\r
+  return MediaSize - (FileSizeSum + (Media->BlockSize + NumFiles));\r
+}\r
+\r
+EFI_STATUS\r
+GetFilesystemInfo (\r
+  IN BOOTMON_FS_INSTANCE *Instance,\r
+  IN OUT UINTN          *BufferSize,\r
+  OUT VOID              *Buffer\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  if (*BufferSize >= Instance->FsInfo.Size) {\r
+    Instance->FsInfo.FreeSpace = ComputeFreeSpace (Instance);\r
+    CopyMem (Buffer, &Instance->FsInfo, Instance->FsInfo.Size);\r
+    Status = EFI_SUCCESS;\r
+  } else {\r
+    Status = EFI_BUFFER_TOO_SMALL;\r
+  }\r
+\r
+  *BufferSize = Instance->FsInfo.Size;\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+GetFileInfo (\r
+  IN BOOTMON_FS_INSTANCE *Instance,\r
+  IN BOOTMON_FS_FILE     *File,\r
+  IN OUT UINTN           *BufferSize,\r
+  OUT VOID               *Buffer\r
+  )\r
+{\r
+  EFI_FILE_INFO   *Info;\r
+  UINTN           ResultSize;\r
+  UINTN           NameSize;\r
+  UINTN           Index;\r
+\r
+  if (File == Instance->RootFile) {\r
+    NameSize = 0;\r
+    ResultSize = SIZE_OF_EFI_FILE_INFO + sizeof (CHAR16);\r
+  } else {\r
+    NameSize   = AsciiStrLen (File->HwDescription.Footer.Filename) + 1;\r
+    ResultSize = SIZE_OF_EFI_FILE_INFO + (NameSize * sizeof (CHAR16));\r
+  }\r
+\r
+  if (*BufferSize < ResultSize) {\r
+    *BufferSize = ResultSize;\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+\r
+  Info = Buffer;\r
+\r
+  // Zero out the structure\r
+  ZeroMem (Info, ResultSize);\r
+\r
+  // Fill in the structure\r
+  Info->Size = ResultSize;\r
+\r
+  if (File == Instance->RootFile) {\r
+    Info->Attribute    = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY;\r
+    Info->FileName[0]  = L'\0';\r
+  } else {\r
+    Info->FileSize     = BootMonFsGetImageLength (File);\r
+    Info->PhysicalSize = BootMonFsGetPhysicalSize (File);\r
+\r
+    for (Index = 0; Index < NameSize; Index++) {\r
+      Info->FileName[Index] = File->HwDescription.Footer.Filename[Index];\r
+    }\r
+  }\r
+\r
+  *BufferSize = ResultSize;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+SetFileName (\r
+  IN  BOOTMON_FS_FILE *File,\r
+  IN  CHAR16          *FileNameUnicode\r
+  )\r
+{\r
+  CHAR8                 *FileNameAscii;\r
+  UINT16                 SavedChar;\r
+  UINTN                  FileNameSize;\r
+  BOOTMON_FS_FILE       *SameFile;\r
+  EFI_STATUS             Status;\r
+\r
+  // EFI Shell inserts '\' in front of the filename that must be stripped\r
+  if (FileNameUnicode[0] == L'\\') {\r
+    FileNameUnicode++;\r
+  }\r
+  //\r
+  // Convert Unicode into Ascii\r
+  //\r
+  SavedChar = L'\0';\r
+  FileNameSize = StrLen (FileNameUnicode) + 1;\r
+  FileNameAscii = AllocatePool (FileNameSize * sizeof (CHAR8));\r
+  if (FileNameAscii == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  // If Unicode string is too long then truncate it.\r
+  if (FileNameSize > MAX_NAME_LENGTH) {\r
+    SavedChar = FileNameUnicode[MAX_NAME_LENGTH - 1];\r
+    FileNameUnicode[MAX_NAME_LENGTH - 1] = L'\0';\r
+  }\r
+  UnicodeStrToAsciiStr (FileNameUnicode, FileNameAscii);\r
+  // If the unicode string was truncated then restore its original content.\r
+  if (SavedChar != L'\0') {\r
+    FileNameUnicode[MAX_NAME_LENGTH - 1] = SavedChar;\r
+  }\r
+\r
+  // If we're changing the file name\r
+  if (AsciiStrCmp (FileNameAscii, File->HwDescription.Footer.Filename)) {\r
+    // Check a file with that filename doesn't already exist\r
+    if (BootMonGetFileFromAsciiFileName (\r
+          File->Instance,\r
+          File->HwDescription.Footer.Filename,\r
+          &SameFile) != EFI_NOT_FOUND) {\r
+      Status = EFI_ACCESS_DENIED;\r
+    } else {\r
+      AsciiStrCpy (FileNameAscii, File->HwDescription.Footer.Filename);\r
+      Status = EFI_SUCCESS;\r
+    }\r
+  } else {\r
+    // No change to filename\r
+    Status = EFI_SUCCESS;\r
+  }\r
+\r
+  FreePool (FileNameAscii);\r
+  return Status;\r
+}\r
+\r
+// Set the file's size (NB "size", not "physical size"). If the change amounts\r
+// to an increase, simply do a write followed by a flush.\r
+// (This is a helper function for SetFileInfo.)\r
+STATIC\r
+EFI_STATUS\r
+SetFileSize (\r
+  IN BOOTMON_FS_INSTANCE *Instance,\r
+  IN BOOTMON_FS_FILE     *BootMonFsFile,\r
+  IN UINTN               Size\r
+  )\r
+{\r
+  UINT64             StoredPosition;\r
+  EFI_STATUS         Status;\r
+  EFI_FILE_PROTOCOL *File;\r
+  CHAR8              Buffer;\r
+  UINTN              BufferSize;\r
+\r
+  Buffer = 0;\r
+  BufferSize = sizeof (Buffer);\r
+\r
+  File = &BootMonFsFile->File;\r
+\r
+  if (!(BootMonFsFile->OpenMode & EFI_FILE_MODE_WRITE)) {\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  if (Size <= BootMonFsFile->HwDescription.Region[0].Size) {\r
+    BootMonFsFile->HwDescription.Region[0].Size = Size;\r
+  } else {\r
+    // Increasing a file's size is potentially complicated as it may require\r
+    // moving the image description on media. The simplest way to do it is to\r
+    // seek past the end of the file (which is valid in UEFI) and perform a\r
+    // Write.\r
+\r
+    // Save position\r
+    Status = File->GetPosition (File, &StoredPosition);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    Status = File->SetPosition (File, Size - 1);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    Status = File->Write (File, &BufferSize, &Buffer);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    // Restore saved position\r
+    Status = File->SetPosition (File, Size - 1);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    Status = File->Flush (File);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+SetFileInfo (\r
+  IN BOOTMON_FS_INSTANCE *Instance,\r
+  IN BOOTMON_FS_FILE     *File,\r
+  IN UINTN                BufferSize,\r
+  IN EFI_FILE_INFO       *Info\r
+  )\r
+{\r
+  EFI_STATUS             Status;\r
+  EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+  UINT8                 *DataBuffer;\r
+  UINTN                  BlockSize;\r
+\r
+  Status  = EFI_SUCCESS;\r
+  BlockIo = Instance->BlockIo;\r
+\r
+  // Note that a call to this function on a file opened read-only is only\r
+  // invalid if it actually changes fields, so  we don't immediately fail if the\r
+  // OpenMode is wrong.\r
+  // Also note that the only fields supported are filename and size, others are\r
+  // ignored.\r
+\r
+  if (File != Instance->RootFile) {\r
+    if (!(File->OpenMode & EFI_FILE_MODE_WRITE)) {\r
+      return EFI_ACCESS_DENIED;\r
+    }\r
+\r
+    SetFileName (File, Info->FileName);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    // Update file size\r
+    Status = SetFileSize (Instance, File, Info->FileSize);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Update the last block\r
+    //\r
+    BlockSize = BlockIo->Media->BlockSize;\r
+    DataBuffer = AllocatePool (BlockSize);\r
+    if (DataBuffer == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    Status = BlockIo->ReadBlocks (BlockIo, Instance->Media->MediaId,\r
+        File->HwDescription.BlockEnd, BlockSize, DataBuffer);\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (DataBuffer);\r
+      return Status;\r
+    }\r
+    CopyMem (DataBuffer + BlockSize - sizeof (File->HwDescription), &File->HwDescription, sizeof (File->HwDescription));\r
+    Status = BlockIo->WriteBlocks (BlockIo, Instance->Media->MediaId,\r
+            File->HwDescription.BlockEnd, BlockSize, DataBuffer);\r
+    FreePool (DataBuffer);\r
+  }\r
+  return Status;\r
+}\r
+\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsGetInfo (\r
+  IN EFI_FILE_PROTOCOL  *This,\r
+  IN EFI_GUID           *InformationType,\r
+  IN OUT UINTN          *BufferSize,\r
+  OUT VOID              *Buffer\r
+  )\r
+{\r
+  EFI_STATUS           Status;\r
+  BOOTMON_FS_FILE     *File;\r
+  BOOTMON_FS_INSTANCE *Instance;\r
+\r
+  File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
+  if (File == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Instance = File->Instance;\r
+\r
+  // If the instance has not been initialized yet then do it ...\r
+  if (!Instance->Initialized) {\r
+    Status = BootMonFsInitialize (Instance);\r
+  } else {\r
+    Status = EFI_SUCCESS;\r
+  }\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)\r
+        != 0) {\r
+      Status = GetFileSystemVolumeLabelInfo (Instance, BufferSize, Buffer);\r
+    } else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid) != 0) {\r
+      Status = GetFilesystemInfo (Instance, BufferSize, Buffer);\r
+    } else if (CompareGuid (InformationType, &gEfiFileInfoGuid) != 0) {\r
+      Status = GetFileInfo (Instance, File, BufferSize, Buffer);\r
+    } else {\r
+      Status = EFI_UNSUPPORTED;\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsSetInfo (\r
+  IN EFI_FILE_PROTOCOL  *This,\r
+  IN EFI_GUID           *InformationType,\r
+  IN UINTN              BufferSize,\r
+  IN VOID               *Buffer\r
+  )\r
+{\r
+  EFI_STATUS           Status;\r
+  BOOTMON_FS_FILE     *File;\r
+  BOOTMON_FS_INSTANCE *Instance;\r
+\r
+  File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
+  if (File == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Instance = File->Instance;\r
+\r
+  if (CompareGuid (InformationType, &gEfiFileInfoGuid) != 0) {\r
+    Status = SetFileInfo (Instance, File, BufferSize, (EFI_FILE_INFO *) Buffer);\r
+  } else {\r
+    // The only writable field in the other two information types\r
+    // (i.e. EFI_FILE_SYSTEM_INFO and EFI_FILE_SYSTEM_VOLUME_LABEL) is the\r
+    // filesystem volume label. This can be retrieved with GetInfo, but it is\r
+    // hard-coded into this driver, not stored on media.\r
+    Status = EFI_UNSUPPORTED;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsReadDirectory (\r
+  IN EFI_FILE_PROTOCOL    *This,\r
+  IN OUT UINTN            *BufferSize,\r
+  OUT VOID                *Buffer\r
+  )\r
+{\r
+  BOOTMON_FS_INSTANCE *Instance;\r
+  BOOTMON_FS_FILE     *RootFile;\r
+  BOOTMON_FS_FILE     *File;\r
+  EFI_FILE_INFO       *Info;\r
+  UINTN               NameSize;\r
+  UINTN               ResultSize;\r
+  EFI_STATUS          Status;\r
+  UINTN               Index;\r
+\r
+  RootFile = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
+  if (RootFile == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance = RootFile->Instance;\r
+  Status = BootMonGetFileFromPosition (Instance, RootFile->Position, &File);\r
+  if (EFI_ERROR (Status)) {\r
+    // No more file\r
+    *BufferSize = 0;\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  NameSize   = AsciiStrLen (File->HwDescription.Footer.Filename) + 1;\r
+  ResultSize = SIZE_OF_EFI_FILE_INFO + (NameSize * sizeof (CHAR16));\r
+  if (*BufferSize < ResultSize) {\r
+    *BufferSize = ResultSize;\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+\r
+  // Zero out the structure\r
+  Info = Buffer;\r
+  ZeroMem (Info, ResultSize);\r
+\r
+  // Fill in the structure\r
+  Info->Size         = ResultSize;\r
+  Info->FileSize     = BootMonFsGetImageLength (File);\r
+  Info->PhysicalSize = BootMonFsGetPhysicalSize (File);\r
+  for (Index = 0; Index < NameSize; Index++) {\r
+    Info->FileName[Index] = File->HwDescription.Footer.Filename[Index];\r
+  }\r
+\r
+  *BufferSize = ResultSize;\r
+  RootFile->Position++;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsFlushDirectory (\r
+  IN EFI_FILE_PROTOCOL  *This\r
+  )\r
+{\r
+  BOOTMON_FS_FILE *RootFile;\r
+  LIST_ENTRY      *ListFiles;\r
+  LIST_ENTRY      *Link;\r
+  BOOTMON_FS_FILE *File;\r
+\r
+  RootFile = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
+  if (RootFile == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  ListFiles = &RootFile->Link;\r
+\r
+  if (IsListEmpty (ListFiles)) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Flush all the files that need to be flushed\r
+  //\r
+\r
+  // Go through all the list of files to flush them\r
+  for (Link = GetFirstNode (ListFiles);\r
+       !IsNull (ListFiles, Link);\r
+       Link = GetNextNode (ListFiles, Link)\r
+       )\r
+  {\r
+    File = BOOTMON_FS_FILE_FROM_LINK_THIS (Link);\r
+    File->File.Flush (&File->File);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsEntryPoint.c b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsEntryPoint.c
new file mode 100644 (file)
index 0000000..00f7c07
--- /dev/null
@@ -0,0 +1,479 @@
+/** @file\r
+*\r
+*  Copyright (c) 2012-2014, ARM Limited. All rights reserved.\r
+*\r
+*  This program and the accompanying materials\r
+*  are licensed and made available under the terms and conditions of the BSD License\r
+*  which accompanies this distribution.  The full text of the license may be found at\r
+*  http://opensource.org/licenses/bsd-license.php\r
+*\r
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+*\r
+**/\r
+\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+\r
+#include <Protocol/DevicePathFromText.h>\r
+#include <Protocol/DriverBinding.h>\r
+\r
+#include "BootMonFsInternal.h"\r
+\r
+EFI_DEVICE_PATH* mBootMonFsSupportedDevicePaths;\r
+EFI_HANDLE       mImageHandle;\r
+LIST_ENTRY       mInstances;\r
+\r
+EFI_FILE_PROTOCOL mBootMonFsRootTemplate = {\r
+  EFI_FILE_PROTOCOL_REVISION,\r
+  BootMonFsOpenFile,\r
+  BootMonFsCloseFile,\r
+  BootMonFsDeleteFail,\r
+  BootMonFsReadDirectory,\r
+  BootMonFsWriteFile,\r
+  BootMonFsGetPositionUnsupported,  // UEFI Spec: GetPosition not valid on dirs\r
+  BootMonFsSetDirPosition,\r
+  BootMonFsGetInfo,\r
+  BootMonFsSetInfo,\r
+  BootMonFsFlushDirectory\r
+};\r
+\r
+EFI_FILE_PROTOCOL mBootMonFsFileTemplate = {\r
+  EFI_FILE_PROTOCOL_REVISION,\r
+  BootMonFsOpenFile,\r
+  BootMonFsCloseFile,\r
+  BootMonFsDelete,\r
+  BootMonFsReadFile,\r
+  BootMonFsWriteFile,\r
+  BootMonFsGetPosition,\r
+  BootMonFsSetPosition,\r
+  BootMonFsGetInfo,\r
+  BootMonFsSetInfo,\r
+  BootMonFsFlushFile\r
+};\r
+\r
+EFI_STATUS\r
+BootMonGetFileFromAsciiFileName (\r
+  IN  BOOTMON_FS_INSTANCE   *Instance,\r
+  IN  CHAR8*                AsciiFileName,\r
+  OUT BOOTMON_FS_FILE       **File\r
+  )\r
+{\r
+  LIST_ENTRY        *Entry;\r
+  BOOTMON_FS_FILE   *FileEntry;\r
+\r
+  // Remove the leading '\\'\r
+  if (*AsciiFileName == '\\') {\r
+    AsciiFileName++;\r
+  }\r
+\r
+  // Go through all the files in the list and return the file handle\r
+  for (Entry = GetFirstNode (&Instance->RootFile->Link);\r
+         !IsNull (&Instance->RootFile->Link, Entry);\r
+         Entry = GetNextNode (&Instance->RootFile->Link, Entry)\r
+         )\r
+  {\r
+    FileEntry = BOOTMON_FS_FILE_FROM_LINK_THIS (Entry);\r
+    if (AsciiStrCmp (FileEntry->HwDescription.Footer.Filename, AsciiFileName) == 0) {\r
+      *File = FileEntry;\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+EFI_STATUS\r
+BootMonGetFileFromPosition (\r
+  IN  BOOTMON_FS_INSTANCE   *Instance,\r
+  IN  UINTN                 Position,\r
+  OUT BOOTMON_FS_FILE       **File\r
+  )\r
+{\r
+  LIST_ENTRY        *Entry;\r
+  BOOTMON_FS_FILE   *FileEntry;\r
+\r
+  // Go through all the files in the list and return the file handle\r
+  for (Entry = GetFirstNode (&Instance->RootFile->Link);\r
+       !IsNull (&Instance->RootFile->Link, Entry) && (&Instance->RootFile->Link != Entry);\r
+       Entry = GetNextNode (&Instance->RootFile->Link, Entry)\r
+       )\r
+  {\r
+    if (Position == 0) {\r
+      FileEntry = BOOTMON_FS_FILE_FROM_LINK_THIS (Entry);\r
+      *File = FileEntry;\r
+      return EFI_SUCCESS;\r
+    }\r
+    Position--;\r
+  }\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+EFI_STATUS\r
+BootMonFsCreateFile (\r
+  IN  BOOTMON_FS_INSTANCE *Instance,\r
+  OUT BOOTMON_FS_FILE     **File\r
+  )\r
+{\r
+  BOOTMON_FS_FILE *NewFile;\r
+\r
+  NewFile = (BOOTMON_FS_FILE*)AllocateZeroPool (sizeof (BOOTMON_FS_FILE));\r
+  if (NewFile == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  NewFile->Signature = BOOTMON_FS_FILE_SIGNATURE;\r
+  InitializeListHead (&NewFile->Link);\r
+  InitializeListHead (&NewFile->RegionToFlushLink);\r
+  NewFile->Instance = Instance;\r
+\r
+  // If the created file is the root file then create a directory EFI_FILE_PROTOCOL\r
+  if (Instance->RootFile == *File) {\r
+    CopyMem (&NewFile->File, &mBootMonFsRootTemplate, sizeof (mBootMonFsRootTemplate));\r
+  } else {\r
+    CopyMem (&NewFile->File, &mBootMonFsFileTemplate, sizeof (mBootMonFsFileTemplate));\r
+  }\r
+  *File = NewFile;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+SupportedDevicePathsInit (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  CHAR16*                             DevicePathListStr;\r
+  CHAR16*                             DevicePathStr;\r
+  CHAR16*                             NextDevicePathStr;\r
+  EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol;\r
+  EFI_DEVICE_PATH_PROTOCOL           *Instance;\r
+\r
+  Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  // Initialize Variable\r
+  DevicePathListStr = (CHAR16*)PcdGetPtr (PcdBootMonFsSupportedDevicePaths);\r
+  mBootMonFsSupportedDevicePaths = NULL;\r
+\r
+  // Extract the Device Path instances from the multi-device path string\r
+  while ((DevicePathListStr != NULL) && (DevicePathListStr[0] != L'\0')) {\r
+    NextDevicePathStr = StrStr (DevicePathListStr, L";");\r
+    if (NextDevicePathStr == NULL) {\r
+      DevicePathStr = DevicePathListStr;\r
+      DevicePathListStr = NULL;\r
+    } else {\r
+      DevicePathStr = (CHAR16*)AllocateCopyPool ((NextDevicePathStr - DevicePathListStr + 1) * sizeof (CHAR16), DevicePathListStr);\r
+      if (DevicePathStr == NULL) {\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+      *(DevicePathStr + (NextDevicePathStr - DevicePathListStr)) = L'\0';\r
+      DevicePathListStr = NextDevicePathStr;\r
+      if (DevicePathListStr[0] == L';') {\r
+        DevicePathListStr++;\r
+      }\r
+    }\r
+\r
+    Instance = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (DevicePathStr);\r
+    ASSERT (Instance != NULL);\r
+    mBootMonFsSupportedDevicePaths = AppendDevicePathInstance (mBootMonFsSupportedDevicePaths, Instance);\r
+\r
+    if (NextDevicePathStr != NULL) {\r
+      FreePool (DevicePathStr);\r
+    }\r
+    FreePool (Instance);\r
+  }\r
+\r
+  if (mBootMonFsSupportedDevicePaths == NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  } else {\r
+    return EFI_SUCCESS;\r
+  }\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+BootMonFsDriverSupported (\r
+  IN        EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,\r
+  IN        EFI_HANDLE                   ControllerHandle,\r
+  IN        EFI_DEVICE_PATH_PROTOCOL    *DevicePath OPTIONAL\r
+  )\r
+{\r
+  EFI_DISK_IO_PROTOCOL  *DiskIo;\r
+  EFI_DEVICE_PATH_PROTOCOL *DevicePathProtocol;\r
+  EFI_DEVICE_PATH_PROTOCOL *SupportedDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL *SupportedDevicePaths;\r
+  EFI_STATUS Status;\r
+  UINTN Size1;\r
+  UINTN Size2;\r
+\r
+  //\r
+  // Open the IO Abstraction(s) needed to perform the supported test\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiDiskIoProtocolGuid,\r
+                  (VOID **) &DiskIo,\r
+                  mImageHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Close the I/O Abstraction(s) used to perform the supported test\r
+  //\r
+  gBS->CloseProtocol (\r
+         ControllerHandle,\r
+         &gEfiDiskIoProtocolGuid,\r
+         mImageHandle,\r
+         ControllerHandle\r
+         );\r
+\r
+  // Check that BlockIo protocol instance exists\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiBlockIoProtocolGuid,\r
+                  NULL,\r
+                  mImageHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  // Check if a DevicePath is attached to the handle\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  (VOID **)&DevicePathProtocol,\r
+                  mImageHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  // Check if the Device Path is the one which contains the Boot Monitor File System\r
+  Size1 = GetDevicePathSize (DevicePathProtocol);\r
+\r
+  // Go through the list of Device Path Instances\r
+  Status = EFI_UNSUPPORTED;\r
+  SupportedDevicePaths = mBootMonFsSupportedDevicePaths;\r
+  while (SupportedDevicePaths != NULL) {\r
+    SupportedDevicePath = GetNextDevicePathInstance (&SupportedDevicePaths, &Size2);\r
+\r
+    if ((Size1 == Size2) && (CompareMem (DevicePathProtocol, SupportedDevicePath, Size1) == 0)) {\r
+      // The Device Path is supported\r
+      Status = EFI_SUCCESS;\r
+      break;\r
+    }\r
+  }\r
+\r
+  gBS->CloseProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid, mImageHandle, ControllerHandle);\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+BootMonFsDriverStart (\r
+  IN        EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,\r
+  IN        EFI_HANDLE                   ControllerHandle,\r
+  IN        EFI_DEVICE_PATH_PROTOCOL    *DevicePath OPTIONAL\r
+  )\r
+{\r
+  BOOTMON_FS_INSTANCE *Instance;\r
+  EFI_STATUS           Status;\r
+  UINTN                VolumeNameSize;\r
+\r
+  Instance = AllocateZeroPool (sizeof (BOOTMON_FS_INSTANCE));\r
+  if (Instance == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  // Initialize the BlockIo of the Instance\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiBlockIoProtocolGuid,\r
+                  (VOID **)&(Instance->BlockIo),\r
+                  mImageHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (Instance);\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiDiskIoProtocolGuid,\r
+                  (VOID **)&(Instance->DiskIo),\r
+                  mImageHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (Instance);\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Initialize the attributes of the Instance\r
+  //\r
+  Instance->Signature = BOOTMON_FS_SIGNATURE;\r
+  Instance->ControllerHandle = ControllerHandle;\r
+  Instance->Media = Instance->BlockIo->Media;\r
+  Instance->Binding = DriverBinding;\r
+\r
+    // Initialize the Simple File System Protocol\r
+  Instance->Fs.Revision = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION;\r
+  Instance->Fs.OpenVolume = OpenBootMonFsOpenVolume;\r
+\r
+  // Volume name + L' ' + '2' digit number\r
+  VolumeNameSize = StrSize (BOOTMON_FS_VOLUME_LABEL) + (3 * sizeof (CHAR16));\r
+\r
+  // Initialize FileSystem Information\r
+  Instance->FsInfo.Size = SIZE_OF_EFI_FILE_SYSTEM_INFO + VolumeNameSize;\r
+  Instance->FsInfo.BlockSize = Instance->Media->BlockSize;\r
+  Instance->FsInfo.ReadOnly = FALSE;\r
+  Instance->FsInfo.VolumeSize =\r
+    Instance->Media->BlockSize * (Instance->Media->LastBlock - Instance->Media->LowestAlignedLba);\r
+  CopyMem (Instance->FsInfo.VolumeLabel, BOOTMON_FS_VOLUME_LABEL, StrSize (BOOTMON_FS_VOLUME_LABEL));\r
+\r
+  // Initialize the root file\r
+  Status = BootMonFsCreateFile (Instance, &Instance->RootFile);\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (Instance);\r
+    return Status;\r
+  }\r
+\r
+  // Initialize the DevicePath of the Instance\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  (VOID **)&(Instance->DevicePath),\r
+                  mImageHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (Instance);\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Install the Simple File System Protocol\r
+  //\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                      &ControllerHandle,\r
+                      &gEfiSimpleFileSystemProtocolGuid, &Instance->Fs,\r
+                      NULL\r
+                      );\r
+\r
+  InsertTailList (&mInstances, &Instance->Link);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+BootMonFsDriverStop (\r
+  IN        EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,\r
+  IN        EFI_HANDLE                   ControllerHandle,\r
+  IN        UINTN                        NumberOfChildren,\r
+  IN        EFI_HANDLE                  *ChildHandleBuffer OPTIONAL\r
+  )\r
+{\r
+  BOOTMON_FS_INSTANCE *Instance;\r
+  LIST_ENTRY          *Link;\r
+  EFI_STATUS           Status;\r
+  BOOLEAN              InstanceFound;\r
+\r
+  // Find instance from ControllerHandle.\r
+  Instance = NULL;\r
+  InstanceFound = FALSE;\r
+  // For each instance in mInstances:\r
+  for (Link = GetFirstNode (&mInstances); !IsNull (&mInstances, Link); Link = GetNextNode (&mInstances, Link)) {\r
+    Instance = BOOTMON_FS_FROM_LINK (Link);\r
+\r
+    if (Instance->ControllerHandle == ControllerHandle) {\r
+      InstanceFound = TRUE;\r
+      break;\r
+    }\r
+  }\r
+  ASSERT (InstanceFound == TRUE);\r
+\r
+  gBS->CloseProtocol (\r
+      ControllerHandle,\r
+      &gEfiDevicePathProtocolGuid,\r
+      DriverBinding->ImageHandle,\r
+      ControllerHandle);\r
+\r
+  gBS->CloseProtocol (\r
+      ControllerHandle,\r
+      &gEfiDiskIoProtocolGuid,\r
+      DriverBinding->ImageHandle,\r
+      ControllerHandle);\r
+\r
+  gBS->CloseProtocol (\r
+      ControllerHandle,\r
+      &gEfiBlockIoProtocolGuid,\r
+      DriverBinding->ImageHandle,\r
+      ControllerHandle);\r
+\r
+  Status = gBS->UninstallMultipleProtocolInterfaces (\r
+      &ControllerHandle,\r
+      &gEfiSimpleFileSystemProtocolGuid, &Instance->Fs,\r
+      NULL);\r
+\r
+  return Status;\r
+}\r
+\r
+//\r
+// Simple Network Protocol Driver Global Variables\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL mBootMonFsDriverBinding = {\r
+  BootMonFsDriverSupported,\r
+  BootMonFsDriverStart,\r
+  BootMonFsDriverStop,\r
+  0xa,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+BootMonFsEntryPoint (\r
+  IN EFI_HANDLE                            ImageHandle,\r
+  IN EFI_SYSTEM_TABLE                      *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  mImageHandle = ImageHandle;\r
+  InitializeListHead (&mInstances);\r
+\r
+  // Initialize the list of Device Paths that could support BootMonFs\r
+  Status = SupportedDevicePathsInit ();\r
+  if (!EFI_ERROR (Status)) {\r
+    Status = gBS->InstallMultipleProtocolInterfaces (\r
+                    &ImageHandle,\r
+                    &gEfiDriverBindingProtocolGuid, &mBootMonFsDriverBinding,\r
+                    NULL\r
+                    );\r
+    ASSERT_EFI_ERROR (Status);\r
+  } else {\r
+    DEBUG((EFI_D_ERROR,"Warning: No Device Paths supporting BootMonFs have been defined in the PCD.\n"));\r
+  }\r
+\r
+  return Status;\r
+}\r
diff --git a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsHw.h b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsHw.h
new file mode 100644 (file)
index 0000000..3ebb5ba
--- /dev/null
@@ -0,0 +1,53 @@
+/** @file\r
+*\r
+*  Copyright (c) 2012-2014, ARM Limited. All rights reserved.\r
+*\r
+*  This program and the accompanying materials\r
+*  are licensed and made available under the terms and conditions of the BSD License\r
+*  which accompanies this distribution.  The full text of the license may be found at\r
+*  http://opensource.org/licenses/bsd-license.php\r
+*\r
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+*\r
+**/\r
+\r
+#ifndef __BOOTMON_FS_HW_H__\r
+#define __BOOTMON_FS_HW_H__\r
+\r
+#define MAX_NAME_LENGTH 32\r
+\r
+#define HW_IMAGE_FOOTER_SIGNATURE_1 0x464C5348\r
+#define HW_IMAGE_FOOTER_SIGNATURE_2 0x464F4F54\r
+#define HW_IMAGE_FOOTER_VERSION     1\r
+#define HW_IMAGE_FOOTER_OFFSET      92\r
+\r
+typedef struct {\r
+  CHAR8  Filename[MAX_NAME_LENGTH];\r
+  UINT32 Offset;\r
+  UINT32 Version;\r
+  UINT32 FooterSignature1;\r
+  UINT32 FooterSignature2;\r
+} HW_IMAGE_FOOTER;\r
+\r
+#define HW_IMAGE_DESCRIPTION_REGION_MAX 4\r
+\r
+// This structure is located at the end of a block when a file is present\r
+typedef struct {\r
+  UINT32  EntryPoint;\r
+  UINT32  Attributes;\r
+  UINT32  RegionCount;\r
+  struct {\r
+    UINT32 LoadAddress;\r
+    UINT32 Size;\r
+    UINT32 Offset;\r
+    UINT32 Checksum;\r
+  } Region[HW_IMAGE_DESCRIPTION_REGION_MAX];\r
+  UINT32  BlockStart;\r
+  UINT32  BlockEnd;\r
+  UINT32  FooterChecksum;\r
+\r
+  HW_IMAGE_FOOTER Footer;\r
+} HW_IMAGE_DESCRIPTION;\r
+\r
+#endif\r
diff --git a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsImages.c b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsImages.c
new file mode 100644 (file)
index 0000000..7d3e901
--- /dev/null
@@ -0,0 +1,214 @@
+/** @file\r
+*\r
+*  Copyright (c) 2012-2014, ARM Limited. All rights reserved.\r
+*\r
+*  This program and the accompanying materials\r
+*  are licensed and made available under the terms and conditions of the BSD License\r
+*  which accompanies this distribution.  The full text of the license may be found at\r
+*  http://opensource.org/licenses/bsd-license.php\r
+*\r
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+*\r
+**/\r
+\r
+#include <Library/IoLib.h>\r
+#include <Library/NorFlashPlatformLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+\r
+#include <Protocol/SimpleFileSystem.h>\r
+\r
+#include "BootMonFsInternal.h"\r
+\r
+UINT32\r
+BootMonFsChecksum (\r
+  IN VOID   *Data,\r
+  IN UINT32 Size\r
+  )\r
+{\r
+  UINT32  *Ptr;\r
+  UINT32  Word;\r
+  UINT32  Checksum;\r
+\r
+  ASSERT (Size % 4 == 0);\r
+\r
+  Checksum = 0;\r
+  Ptr = (UINT32*)Data;\r
+\r
+  while (Size > 0) {\r
+    Word = *Ptr++;\r
+    Size -= 4;\r
+\r
+    if (Word > ~Checksum) {\r
+      Checksum++;\r
+    }\r
+\r
+    Checksum += Word;\r
+  }\r
+\r
+  return ~Checksum;\r
+}\r
+\r
+EFI_STATUS\r
+BootMonFsComputeFooterChecksum (\r
+  IN OUT HW_IMAGE_DESCRIPTION *Footer\r
+  )\r
+{\r
+  HW_IMAGE_DESCRIPTION *Description;\r
+  UINT32                Index;\r
+\r
+  Footer->Attributes = 1;\r
+\r
+  Description = AllocateZeroPool (sizeof (HW_IMAGE_DESCRIPTION));\r
+  if (Description == NULL) {\r
+    DEBUG ((DEBUG_ERROR, "BootMonFsComputeFooterChecksum: Unable to allocate memory.\n"));\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  // Copy over to temporary shim\r
+  CopyMem (Description, Footer, sizeof (HW_IMAGE_DESCRIPTION));\r
+\r
+  // BootMon doesn't checksum the previous checksum\r
+  Description->FooterChecksum = 0;\r
+\r
+  // Blank out regions which aren't being used.\r
+  for (Index = Footer->RegionCount; Index < HW_IMAGE_DESCRIPTION_REGION_MAX; Index++) {\r
+    Description->Region[Index].Checksum = 0;\r
+    Description->Region[Index].LoadAddress = 0;\r
+    Description->Region[Index].Offset = 0;\r
+    Description->Region[Index].Size = 0;\r
+  }\r
+\r
+  // Compute the checksum\r
+  Footer->FooterChecksum = BootMonFsChecksum (Description, sizeof (HW_IMAGE_DESCRIPTION));\r
+\r
+  FreePool (Description);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+BOOLEAN\r
+BootMonFsImageInThisBlock (\r
+  IN  VOID                  *Buf,\r
+  IN  UINTN                  Size,\r
+  IN  UINT32                 Block,\r
+  OUT HW_IMAGE_DESCRIPTION  *Image\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  HW_IMAGE_FOOTER      *Ptr;\r
+  HW_IMAGE_DESCRIPTION *Footer;\r
+  UINT32                Checksum;\r
+\r
+  // The footer is stored as the last thing in the block\r
+  Ptr = (HW_IMAGE_FOOTER *)((UINT8 *)Buf + Size - sizeof (HW_IMAGE_FOOTER));\r
+\r
+  // Check that the verification bytes are present\r
+  if ((Ptr->FooterSignature1 != HW_IMAGE_FOOTER_SIGNATURE_1) || (Ptr->FooterSignature2 != HW_IMAGE_FOOTER_SIGNATURE_2)) {\r
+    return FALSE;\r
+  }\r
+\r
+  if (Ptr->Version != HW_IMAGE_FOOTER_VERSION) {\r
+    return FALSE;\r
+  }\r
+\r
+  if (Ptr->Offset != HW_IMAGE_FOOTER_OFFSET) {\r
+    return FALSE;\r
+  }\r
+\r
+  Footer = (HW_IMAGE_DESCRIPTION *)(((UINT8 *)Buf + Size - sizeof (HW_IMAGE_DESCRIPTION)));\r
+  Checksum = Footer->FooterChecksum;\r
+  Status = BootMonFsComputeFooterChecksum (Footer);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "Warning: failed to compute checksum for image '%a'\n", Footer->Footer.Filename));\r
+  }\r
+\r
+  if (Footer->FooterChecksum != Checksum) {\r
+    DEBUG ((DEBUG_ERROR, "Warning: image '%a' checksum mismatch.\n", Footer->Footer.Filename));\r
+  }\r
+\r
+  if ((Footer->BlockEnd != Block) || (Footer->BlockStart > Footer->BlockEnd)) {\r
+    return FALSE;\r
+  }\r
+\r
+  // Copy the image out\r
+  CopyMem (Image, Footer, sizeof (HW_IMAGE_DESCRIPTION));\r
+\r
+  return TRUE;\r
+}\r
+\r
+EFI_STATUS\r
+BootMonFsDiscoverNextImage (\r
+  IN BOOTMON_FS_INSTANCE      *Instance,\r
+  IN EFI_LBA                  *LbaStart,\r
+  OUT HW_IMAGE_DESCRIPTION    *Image\r
+  )\r
+{\r
+  EFI_BLOCK_IO_PROTOCOL *Blocks;\r
+  EFI_LBA                CurrentLba;\r
+  VOID                  *Out;\r
+\r
+  Blocks = Instance->BlockIo;\r
+\r
+  // Allocate an output buffer\r
+  Out = AllocatePool (Instance->Media->BlockSize);\r
+  if (Out == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Blocks->Reset (Blocks, FALSE);\r
+  CurrentLba = *LbaStart;\r
+\r
+  // Look for images in the rest of this block\r
+  while (CurrentLba <= Instance->Media->LastBlock) {\r
+    // Read in the next block\r
+    Blocks->ReadBlocks (Blocks, Instance->Media->MediaId, CurrentLba, Instance->Media->BlockSize, Out);\r
+    // Check for an image in the current block\r
+    if (BootMonFsImageInThisBlock (Out, Instance->Media->BlockSize, (CurrentLba - Instance->Media->LowestAlignedLba), Image)) {\r
+      DEBUG ((EFI_D_ERROR, "Found image: %a in block %d.\n", &(Image->Footer.Filename), (UINTN)(CurrentLba - Instance->Media->LowestAlignedLba)));\r
+      FreePool (Out);\r
+      *LbaStart = Image->BlockEnd + 1;\r
+      return EFI_SUCCESS;\r
+    } else {\r
+      CurrentLba++;\r
+    }\r
+  }\r
+\r
+  *LbaStart = CurrentLba;\r
+  FreePool (Out);\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+EFI_STATUS\r
+BootMonFsInitialize (\r
+  IN BOOTMON_FS_INSTANCE *Instance\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  EFI_LBA                  Lba;\r
+  UINT32                   ImageCount;\r
+  BOOTMON_FS_FILE          *NewFile;\r
+\r
+  ImageCount = 0;\r
+  Lba = 0;\r
+\r
+  while (1) {\r
+    Status = BootMonFsCreateFile (Instance, &NewFile);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    Status = BootMonFsDiscoverNextImage (Instance, &Lba, &(NewFile->HwDescription));\r
+    if (EFI_ERROR (Status)) {\r
+      // Free NewFile allocated by BootMonFsCreateFile ()\r
+      FreePool (NewFile);\r
+      break;\r
+    }\r
+    InsertTailList (&Instance->RootFile->Link, &NewFile->Link);\r
+    ImageCount++;\r
+  }\r
+\r
+  Instance->Initialized = TRUE;\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsInternal.h b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsInternal.h
new file mode 100644 (file)
index 0000000..8bcbac6
--- /dev/null
@@ -0,0 +1,93 @@
+/** @file\r
+*\r
+*  Copyright (c) 2012-2014, ARM Limited. All rights reserved.\r
+*\r
+*  This program and the accompanying materials\r
+*  are licensed and made available under the terms and conditions of the BSD License\r
+*  which accompanies this distribution.  The full text of the license may be found at\r
+*  http://opensource.org/licenses/bsd-license.php\r
+*\r
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+*\r
+**/\r
+\r
+#ifndef __BOOTMONFS_INTERNAL_H__\r
+#define __BOOTMONFS_INTERNAL_H__\r
+\r
+#include <PiDxe.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+\r
+#include <Protocol/BlockIo.h>\r
+#include <Protocol/DiskIo.h>\r
+#include <Protocol/FirmwareVolumeBlock.h>\r
+#include <Protocol/SimpleFileSystem.h>\r
+\r
+#include <Guid/FileInfo.h>\r
+#include <Guid/FileSystemInfo.h>\r
+#include <Guid/FileSystemVolumeLabelInfo.h>\r
+\r
+#include "BootMonFsHw.h"\r
+\r
+#define BOOTMON_FS_VOLUME_LABEL   L"NOR Flash"\r
+\r
+typedef struct _BOOTMON_FS_INSTANCE BOOTMON_FS_INSTANCE;\r
+\r
+typedef struct {\r
+  LIST_ENTRY            Link;\r
+  VOID*                 Buffer;\r
+  UINTN                 Size;\r
+  UINT64                Offset; // Offset from the start of the file\r
+} BOOTMON_FS_FILE_REGION;\r
+\r
+typedef struct {\r
+  UINT32                Signature;\r
+  LIST_ENTRY            Link;\r
+  BOOTMON_FS_INSTANCE   *Instance;\r
+\r
+  HW_IMAGE_DESCRIPTION  HwDescription;\r
+\r
+  EFI_FILE_PROTOCOL     File;\r
+\r
+  UINT64                Position;\r
+  // If the file needs to be flushed then this list contain the memory buffer that creates this file\r
+  LIST_ENTRY            RegionToFlushLink;\r
+  UINT64                OpenMode;\r
+} BOOTMON_FS_FILE;\r
+\r
+#define BOOTMON_FS_FILE_SIGNATURE              SIGNATURE_32('b', 'o', 't', 'f')\r
+#define BOOTMON_FS_FILE_FROM_FILE_THIS(a)      CR (a, BOOTMON_FS_FILE, File, BOOTMON_FS_FILE_SIGNATURE)\r
+#define BOOTMON_FS_FILE_FROM_LINK_THIS(a)      CR (a, BOOTMON_FS_FILE, Link, BOOTMON_FS_FILE_SIGNATURE)\r
+\r
+struct _BOOTMON_FS_INSTANCE {\r
+  UINT32                               Signature;\r
+  EFI_HANDLE                           ControllerHandle;\r
+\r
+  LIST_ENTRY                           Link;\r
+\r
+  EFI_DRIVER_BINDING_PROTOCOL         *Binding;\r
+  EFI_DISK_IO_PROTOCOL                *DiskIo;\r
+  EFI_BLOCK_IO_PROTOCOL               *BlockIo;\r
+  EFI_BLOCK_IO_MEDIA                  *Media;\r
+  EFI_DEVICE_PATH_PROTOCOL            *DevicePath;\r
+\r
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL      Fs;\r
+\r
+  EFI_FILE_SYSTEM_INFO                 FsInfo;\r
+  CHAR16                               Label[20];\r
+\r
+  BOOTMON_FS_FILE                     *RootFile; // All the other files are linked to this root\r
+  BOOLEAN                              Initialized;\r
+};\r
+\r
+#define BOOTMON_FS_SIGNATURE            SIGNATURE_32('b', 'o', 't', 'm')\r
+#define BOOTMON_FS_FROM_FS_THIS(a)      CR (a, BOOTMON_FS_INSTANCE, Fs, BOOTMON_FS_SIGNATURE)\r
+#define BOOTMON_FS_FROM_LINK(a)         CR (a, BOOTMON_FS_INSTANCE, Link, BOOTMON_FS_SIGNATURE)\r
+\r
+#include "BootMonFsApi.h"\r
+\r
+#endif\r
+\r
diff --git a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsOpenClose.c b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsOpenClose.c
new file mode 100644 (file)
index 0000000..908393f
--- /dev/null
@@ -0,0 +1,628 @@
+/** @file\r
+*\r
+*  Copyright (c) 2012-2014, ARM Limited. All rights reserved.\r
+*\r
+*  This program and the accompanying materials\r
+*  are licensed and made available under the terms and conditions of the BSD License\r
+*  which accompanies this distribution.  The full text of the license may be found at\r
+*  http://opensource.org/licenses/bsd-license.php\r
+*\r
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+*\r
+**/\r
+\r
+#include "BootMonFsInternal.h"\r
+\r
+// Clear a file's image description on storage media:\r
+// UEFI allows you to seek past the end of a file, a subsequent write will grow\r
+// the file. It does not specify how space between the former end of the file\r
+// and the beginning of the write should be filled. It's therefore possible that\r
+// BootMonFs metadata, that comes after the end of a file, could be left there\r
+// and wrongly detected by BootMonFsImageInBlock.\r
+STATIC\r
+EFI_STATUS\r
+InvalidateImageDescription (\r
+  IN  BOOTMON_FS_FILE  *File\r
+  )\r
+{\r
+  EFI_DISK_IO_PROTOCOL   *DiskIo;\r
+  EFI_BLOCK_IO_PROTOCOL  *BlockIo;\r
+  UINT32                  MediaId;\r
+  UINT32                  BlockSize;\r
+  VOID                   *Buffer;\r
+  EFI_STATUS              Status;\r
+  UINT64                  DescriptionAddress;\r
+\r
+  DiskIo = File->Instance->DiskIo;\r
+  BlockIo = File->Instance->BlockIo;\r
+  MediaId = BlockIo->Media->MediaId;\r
+  BlockSize = BlockIo->Media->BlockSize;\r
+\r
+  DescriptionAddress = (File->HwDescription.BlockEnd * BlockSize)\r
+                       - sizeof (HW_IMAGE_DESCRIPTION);\r
+\r
+  Buffer = AllocateZeroPool (sizeof (HW_IMAGE_DESCRIPTION));\r
+\r
+  Status = DiskIo->WriteDisk (DiskIo,\r
+                    MediaId,\r
+                    DescriptionAddress,\r
+                    sizeof (HW_IMAGE_DESCRIPTION),\r
+                    Buffer\r
+                    );\r
+\r
+  FreePool(Buffer);\r
+\r
+  return Status;\r
+}\r
+\r
+// Flush file data that will extend the file's length. Update and, if necessary,\r
+// move the image description.\r
+// We need to pass the file's starting position on media (FileStart), because\r
+// if the file hasn't been flushed before its Description->BlockStart won't\r
+// have been initialised.\r
+// FileStart must be aligned to the media's block size.\r
+// Note that this function uses DiskIo to flush, so call BlockIo->FlushBlocks()\r
+// after calling it.\r
+STATIC\r
+EFI_STATUS\r
+FlushAppendRegion (\r
+  IN BOOTMON_FS_FILE         *File,\r
+  IN BOOTMON_FS_FILE_REGION  *Region,\r
+  IN UINT64                   NewFileSize,\r
+  IN UINT64                   FileStart\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  EFI_DISK_IO_PROTOCOL    *DiskIo;\r
+  UINTN                    BlockSize;\r
+  HW_IMAGE_DESCRIPTION    *Description;\r
+\r
+  DiskIo = File->Instance->DiskIo;\r
+\r
+  BlockSize = File->Instance->BlockIo->Media->BlockSize;\r
+\r
+  ASSERT (FileStart % BlockSize == 0);\r
+\r
+  // Only invalidate the Image Description of files that have already been\r
+  // written in Flash\r
+  if (File->HwDescription.RegionCount > 0) {\r
+    Status = InvalidateImageDescription (File);\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+\r
+  //\r
+  // Update File Description\r
+  //\r
+  Description = &File->HwDescription;\r
+  Description->Attributes = 1;\r
+  Description->BlockStart = FileStart / BlockSize;\r
+  Description->BlockEnd = Description->BlockStart + (NewFileSize / BlockSize);\r
+  Description->Footer.FooterSignature1 = HW_IMAGE_FOOTER_SIGNATURE_1;\r
+  Description->Footer.FooterSignature2 = HW_IMAGE_FOOTER_SIGNATURE_2;\r
+  Description->Footer.Version = HW_IMAGE_FOOTER_VERSION;\r
+  Description->Footer.Offset = HW_IMAGE_FOOTER_OFFSET;\r
+  Description->RegionCount = 1;\r
+  Description->Region[0].Checksum = 0;\r
+  Description->Region[0].Offset = Description->BlockStart * BlockSize;\r
+  Description->Region[0].Size = NewFileSize - sizeof (HW_IMAGE_DESCRIPTION);\r
+\r
+  Status = BootMonFsComputeFooterChecksum (Description);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  // Write the new file data\r
+  Status = DiskIo->WriteDisk (\r
+                    DiskIo,\r
+                    File->Instance->Media->MediaId,\r
+                    FileStart + Region->Offset,\r
+                    Region->Size,\r
+                    Region->Buffer\r
+                    );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  // Round the file size up to the nearest block size\r
+  if ((NewFileSize % BlockSize) > 0) {\r
+    NewFileSize += BlockSize - (NewFileSize % BlockSize);\r
+  }\r
+  // Update the file description on the media\r
+  Status = DiskIo->WriteDisk (\r
+                    DiskIo,\r
+                    File->Instance->Media->MediaId,\r
+                    (FileStart + NewFileSize) - sizeof (HW_IMAGE_DESCRIPTION),\r
+                    sizeof (HW_IMAGE_DESCRIPTION),\r
+                    Description\r
+                    );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return Status;\r
+}\r
+\r
+BOOLEAN\r
+BootMonFsFileNeedFlush (\r
+  IN BOOTMON_FS_FILE         *File\r
+  )\r
+{\r
+  return !IsListEmpty (&File->RegionToFlushLink);\r
+}\r
+\r
+// Find a space on media for a file that has not yet been flushed to disk.\r
+// Just returns the first space that's big enough.\r
+// This function could easily be adapted to:\r
+// - Find space for moving an existing file that has outgrown its space\r
+//   (We do not currently move files, just return EFI_VOLUME_FULL)\r
+// - Find space for a fragment of a file that has outgrown its space\r
+//   (We do not currently fragment files - it's not clear whether fragmentation\r
+//    is actually part of BootMonFs as there is no spec)\r
+// - Be more clever about finding space (choosing the largest or smallest\r
+//   suitable space)\r
+// Parameters:\r
+// File - the new (not yet flushed) file for which we need to find space.\r
+// FileStart - the position on media of the file (in bytes).\r
+STATIC\r
+EFI_STATUS\r
+BootMonFsFindSpaceForNewFile (\r
+  IN  BOOTMON_FS_FILE     *File,\r
+  OUT UINT64              *FileStart\r
+  )\r
+{\r
+  LIST_ENTRY              *FileLink;\r
+  BOOTMON_FS_FILE         *RootFile;\r
+  BOOTMON_FS_FILE         *FileEntry;\r
+  UINTN                    BlockSize;\r
+  UINT64                   FileSize;\r
+  EFI_BLOCK_IO_MEDIA      *Media;\r
+\r
+  Media = File->Instance->BlockIo->Media;\r
+  BlockSize = Media->BlockSize;\r
+  RootFile = File->Instance->RootFile;\r
+\r
+  if (IsListEmpty (&RootFile->Link)) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  // This function must only be called for file which has not been flushed into\r
+  // Flash yet\r
+  ASSERT (File->HwDescription.RegionCount == 0);\r
+\r
+  // Find out how big the file will be\r
+  FileSize = BootMonFsGetImageLength (File);\r
+  // Add the file header to the file\r
+  FileSize += sizeof (HW_IMAGE_DESCRIPTION);\r
+\r
+  *FileStart = 0;\r
+  // Go through all the files in the list\r
+  for (FileLink = GetFirstNode (&RootFile->Link);\r
+         !IsNull (&RootFile->Link, FileLink);\r
+         FileLink = GetNextNode (&RootFile->Link, FileLink)\r
+         )\r
+  {\r
+    FileEntry = BOOTMON_FS_FILE_FROM_LINK_THIS (FileLink);\r
+    // If the free space preceding the file is big enough to contain the new\r
+    // file then use it!\r
+    if (((FileEntry->HwDescription.BlockStart * BlockSize) - *FileStart)\r
+        >= FileSize) {\r
+      // The file list must be in disk-order\r
+      RemoveEntryList (&File->Link);\r
+      File->Link.BackLink = FileLink->BackLink;\r
+      File->Link.ForwardLink = FileLink;\r
+      FileLink->BackLink->ForwardLink = &File->Link;\r
+      FileLink->BackLink = &File->Link;\r
+\r
+      return EFI_SUCCESS;\r
+    } else {\r
+      *FileStart = (FileEntry->HwDescription.BlockEnd + 1) * BlockSize;\r
+    }\r
+  }\r
+  // See if there's space after the last file\r
+  if ((((Media->LastBlock + 1) * BlockSize) - *FileStart) >= FileSize) {\r
+    return EFI_SUCCESS;\r
+  } else {\r
+    return EFI_VOLUME_FULL;\r
+  }\r
+}\r
+\r
+// Free the resources in the file's Region list.\r
+STATIC\r
+VOID\r
+FreeFileRegions (\r
+  IN  BOOTMON_FS_FILE *File\r
+  )\r
+{\r
+  LIST_ENTRY              *RegionToFlushLink;\r
+  BOOTMON_FS_FILE_REGION  *Region;\r
+\r
+  RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);\r
+  while (!IsNull (&File->RegionToFlushLink, RegionToFlushLink)) {\r
+    // Repeatedly remove the first node from the list and free its resources.\r
+    Region = (BOOTMON_FS_FILE_REGION *) RegionToFlushLink;\r
+    RemoveEntryList (RegionToFlushLink);\r
+    FreePool (Region->Buffer);\r
+    FreePool (Region);\r
+\r
+    RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);\r
+  }\r
+}\r
+\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsFlushFile (\r
+  IN EFI_FILE_PROTOCOL  *This\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  BOOTMON_FS_INSTANCE     *Instance;\r
+  LIST_ENTRY              *RegionToFlushLink;\r
+  BOOTMON_FS_FILE         *File;\r
+  BOOTMON_FS_FILE         *NextFile;\r
+  BOOTMON_FS_FILE_REGION  *Region;\r
+  LIST_ENTRY              *FileLink;\r
+  UINTN                    CurrentPhysicalSize;\r
+  UINTN                    BlockSize;\r
+  UINT64                   FileStart;\r
+  UINT64                   FileEnd;\r
+  UINT64                   RegionStart;\r
+  UINT64                   RegionEnd;\r
+  UINT64                   NewFileSize;\r
+  UINT64                   EndOfAppendSpace;\r
+  BOOLEAN                  HasSpace;\r
+  EFI_DISK_IO_PROTOCOL    *DiskIo;\r
+  EFI_BLOCK_IO_PROTOCOL   *BlockIo;\r
+\r
+  Status      = EFI_SUCCESS;\r
+  FileStart   = 0;\r
+\r
+  File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
+  if (File == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  // Check if the file needs to be flushed\r
+  if (!BootMonFsFileNeedFlush (File)) {\r
+    return Status;\r
+  }\r
+\r
+  Instance = File->Instance;\r
+  BlockIo = Instance->BlockIo;\r
+  DiskIo = Instance->DiskIo;\r
+  BlockSize = BlockIo->Media->BlockSize;\r
+\r
+  // If the file doesn't exist then find a space for it\r
+  if (File->HwDescription.RegionCount == 0) {\r
+    Status = BootMonFsFindSpaceForNewFile (File, &FileStart);\r
+    // FileStart has changed so we need to recompute RegionEnd\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  } else {\r
+    FileStart = File->HwDescription.BlockStart * BlockSize;\r
+  }\r
+\r
+  // FileEnd is the NOR address of the end of the file's data\r
+  FileEnd = FileStart + BootMonFsGetImageLength (File);\r
+\r
+  for (RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);\r
+       !IsNull (&File->RegionToFlushLink, RegionToFlushLink);\r
+       RegionToFlushLink = GetNextNode (&File->RegionToFlushLink, RegionToFlushLink)\r
+       )\r
+  {\r
+    Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink;\r
+\r
+    // RegionStart and RegionEnd are the the intended NOR address of the\r
+    // start and end of the region\r
+    RegionStart = FileStart + Region->Offset;\r
+    RegionEnd = RegionStart + Region->Size;\r
+\r
+    if (RegionEnd < FileEnd) {\r
+      // Handle regions representing edits to existing portions of the file\r
+      // Write the region data straight into the file\r
+      Status = DiskIo->WriteDisk (DiskIo,\r
+                        BlockIo->Media->MediaId,\r
+                        RegionStart,\r
+                        Region->Size,\r
+                        Region->Buffer\r
+                        );\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+    } else {\r
+      // Handle regions representing appends to the file\r
+      //\r
+      // Note: Since seeking past the end of the file with SetPosition() is\r
+      //  valid, it's possible there will be a gap between the current end of\r
+      //  the file and the beginning of the new region. Since the UEFI spec\r
+      //  says nothing about this case (except "a subsequent write would grow\r
+      //  the file"), we just leave garbage in the gap.\r
+\r
+      // Check if there is space to append the new region\r
+      HasSpace = FALSE;\r
+      NewFileSize = (RegionEnd - FileStart) + sizeof (HW_IMAGE_DESCRIPTION);\r
+      CurrentPhysicalSize = BootMonFsGetPhysicalSize (File);\r
+      if (NewFileSize <= CurrentPhysicalSize) {\r
+        HasSpace = TRUE;\r
+      } else {\r
+        // Get the File Description for the next file\r
+        FileLink = GetNextNode (&Instance->RootFile->Link, &File->Link);\r
+        if (!IsNull (&Instance->RootFile->Link, FileLink)) {\r
+          NextFile = BOOTMON_FS_FILE_FROM_LINK_THIS (FileLink);\r
+\r
+          // If there is space between the beginning of the current file and the\r
+          // beginning of the next file then use it\r
+          EndOfAppendSpace = NextFile->HwDescription.BlockStart * BlockSize;\r
+        } else {\r
+          // We are flushing the last file.\r
+          EndOfAppendSpace = (BlockIo->Media->LastBlock + 1) * BlockSize;\r
+        }\r
+        if (EndOfAppendSpace - FileStart >= NewFileSize) {\r
+          HasSpace = TRUE;\r
+        }\r
+      }\r
+\r
+      if (HasSpace == TRUE) {\r
+        Status = FlushAppendRegion (File, Region, NewFileSize, FileStart);\r
+        if (EFI_ERROR (Status)) {\r
+          return Status;\r
+        }\r
+      } else {\r
+        // There isn't a space for the file.\r
+        // Options here are to move the file or fragment it. However as files\r
+        // may represent boot images at fixed positions, these options will\r
+        // break booting if the bootloader doesn't use BootMonFs to find the\r
+        // image.\r
+\r
+        return EFI_VOLUME_FULL;\r
+      }\r
+    }\r
+  }\r
+\r
+  FreeFileRegions (File);\r
+\r
+  // Flush DiskIo Buffers (see UEFI Spec 12.7 - DiskIo buffers are flushed by\r
+  // calling FlushBlocks on the same device's BlockIo).\r
+  BlockIo->FlushBlocks (BlockIo);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Closes a file on the Nor Flash FS volume.\r
+\r
+  @param  This  The EFI_FILE_PROTOCOL to close.\r
+\r
+  @return Always returns EFI_SUCCESS.\r
+\r
+**/\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsCloseFile (\r
+  IN EFI_FILE_PROTOCOL  *This\r
+  )\r
+{\r
+  // Flush the file if needed\r
+  This->Flush (This);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+// Create a new instance of BOOTMON_FS_FILE.\r
+// Uses BootMonFsCreateFile to\r
+STATIC\r
+EFI_STATUS\r
+CreateNewFile (\r
+  IN  BOOTMON_FS_INSTANCE  *Instance,\r
+  IN  CHAR8*                AsciiFileName,\r
+  OUT BOOTMON_FS_FILE     **NewHandle\r
+  )\r
+{\r
+  EFI_STATUS       Status;\r
+  BOOTMON_FS_FILE *File;\r
+\r
+  Status = BootMonFsCreateFile (Instance, &File);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  // Remove the leading '\\'\r
+  if (*AsciiFileName == '\\') {\r
+    AsciiFileName++;\r
+  }\r
+\r
+  // Set the file name\r
+  CopyMem (File->HwDescription.Footer.Filename, AsciiFileName, MAX_NAME_LENGTH);\r
+\r
+  // Add the file to list of files of the File System\r
+  InsertHeadList (&Instance->RootFile->Link, &File->Link);\r
+\r
+  *NewHandle = File;\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Opens a file on the Nor Flash FS volume\r
+\r
+  Calls BootMonFsGetFileFromAsciiFilename to search the list of tracked files.\r
+\r
+  @param  This  The EFI_FILE_PROTOCOL parent handle.\r
+  @param  NewHandle Double-pointer to the newly created protocol.\r
+  @param  FileName The name of the image/metadata on flash\r
+  @param  OpenMode Read,write,append etc\r
+  @param  Attributes ?\r
+\r
+  @return EFI_STATUS\r
+  OUT_OF_RESOURCES\r
+    Run out of space to keep track of the allocated structures\r
+  DEVICE_ERROR\r
+    Unable to locate the volume associated with the parent file handle\r
+  NOT_FOUND\r
+    Filename wasn't found on flash\r
+  SUCCESS\r
+\r
+**/\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsOpenFile (\r
+  IN EFI_FILE_PROTOCOL  *This,\r
+  OUT EFI_FILE_PROTOCOL **NewHandle,\r
+  IN CHAR16             *FileName,\r
+  IN UINT64             OpenMode,\r
+  IN UINT64             Attributes\r
+  )\r
+{\r
+  BOOTMON_FS_FILE     *Directory;\r
+  BOOTMON_FS_FILE     *File;\r
+  BOOTMON_FS_INSTANCE *Instance;\r
+  CHAR8*               AsciiFileName;\r
+  EFI_STATUS           Status;\r
+\r
+  if ((FileName == NULL) || (NewHandle == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  // The only valid modes are read, read/write, and read/write/create\r
+  if (!(OpenMode & EFI_FILE_MODE_READ) || ((OpenMode & EFI_FILE_MODE_CREATE)  && !(OpenMode & EFI_FILE_MODE_WRITE))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Directory = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
+  if (Directory == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Instance = Directory->Instance;\r
+\r
+  // If the instance has not been initialized it yet then do it ...\r
+  if (!Instance->Initialized) {\r
+    Status = BootMonFsInitialize (Instance);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  // BootMonFs interface requires ASCII filenames\r
+  AsciiFileName = AllocatePool ((StrLen (FileName) + 1) * sizeof (CHAR8));\r
+  if (AsciiFileName == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  UnicodeStrToAsciiStr (FileName, AsciiFileName);\r
+\r
+  if ((AsciiStrCmp (AsciiFileName, "\\") == 0) ||\r
+      (AsciiStrCmp (AsciiFileName, "/")  == 0) ||\r
+      (AsciiStrCmp (AsciiFileName, "")   == 0) ||\r
+      (AsciiStrCmp (AsciiFileName, ".")  == 0))\r
+  {\r
+    //\r
+    // Opening '/', '\', '.', or the NULL pathname is trying to open the root directory\r
+    //\r
+\r
+    *NewHandle = &Instance->RootFile->File;\r
+    Instance->RootFile->Position = 0;\r
+    Status = EFI_SUCCESS;\r
+  } else {\r
+    //\r
+    // Open or Create a regular file\r
+    //\r
+\r
+    // Check if the file already exists\r
+    Status = BootMonGetFileFromAsciiFileName (Instance, AsciiFileName, &File);\r
+    if (Status == EFI_NOT_FOUND) {\r
+      // The file doesn't exist.\r
+      if (OpenMode & EFI_FILE_MODE_CREATE) {\r
+        // If the file does not exist but is required then create it.\r
+        if (Attributes & EFI_FILE_DIRECTORY) {\r
+          // BootMonFS doesn't support subdirectories\r
+          Status = EFI_UNSUPPORTED;\r
+        } else {\r
+          // Create a new file\r
+          Status = CreateNewFile (Instance, AsciiFileName, &File);\r
+          if (!EFI_ERROR (Status)) {\r
+            File->OpenMode = OpenMode;\r
+            *NewHandle = &File->File;\r
+            File->Position = 0;\r
+          }\r
+        }\r
+      }\r
+    } else if (Status == EFI_SUCCESS) {\r
+      // The file exists\r
+      File->OpenMode = OpenMode;\r
+      *NewHandle = &File->File;\r
+      File->Position = 0;\r
+    }\r
+  }\r
+\r
+  FreePool (AsciiFileName);\r
+\r
+  return Status;\r
+}\r
+\r
+// Delete() for the root directory's EFI_FILE_PROTOCOL instance\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsDeleteFail (\r
+  IN EFI_FILE_PROTOCOL *This\r
+  )\r
+{\r
+  This->Close(This);\r
+  // You can't delete the root directory\r
+  return EFI_WARN_DELETE_FAILURE;\r
+}\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsDelete (\r
+  IN EFI_FILE_PROTOCOL *This\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  BOOTMON_FS_FILE         *File;\r
+  LIST_ENTRY              *RegionToFlushLink;\r
+  BOOTMON_FS_FILE_REGION  *Region;\r
+  HW_IMAGE_DESCRIPTION    *Description;\r
+  EFI_BLOCK_IO_PROTOCOL   *BlockIo;\r
+  UINT8                   *EmptyBuffer;\r
+\r
+  File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
+  if (File == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  if (BootMonFsFileNeedFlush (File)) {\r
+    // Free the entries from the Buffer List\r
+    RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);\r
+    do {\r
+      Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink;\r
+\r
+      // Get Next entry\r
+      RegionToFlushLink = RemoveEntryList (RegionToFlushLink);\r
+\r
+      // Free the buffers\r
+      FreePool (Region->Buffer);\r
+      FreePool (Region);\r
+    } while (!IsListEmpty (&File->RegionToFlushLink));\r
+  }\r
+\r
+  // If (RegionCount is greater than 0) then the file already exists\r
+  if (File->HwDescription.RegionCount > 0) {\r
+    Description = &File->HwDescription;\r
+    BlockIo = File->Instance->BlockIo;\r
+\r
+    // Create an empty buffer\r
+    EmptyBuffer = AllocateZeroPool (BlockIo->Media->BlockSize);\r
+    if (EmptyBuffer == NULL) {\r
+      FreePool (File);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    // Invalidate the last Block\r
+    Status = BlockIo->WriteBlocks (BlockIo, BlockIo->Media->MediaId, Description->BlockEnd, BlockIo->Media->BlockSize, EmptyBuffer);\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    FreePool (EmptyBuffer);\r
+  }\r
+\r
+  // Remove the entry from the list\r
+  RemoveEntryList (&File->Link);\r
+  FreePool (File);\r
+  return Status;\r
+}\r
+\r
diff --git a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsReadWrite.c b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsReadWrite.c
new file mode 100644 (file)
index 0000000..653b2c5
--- /dev/null
@@ -0,0 +1,163 @@
+/** @file\r
+*\r
+*  Copyright (c) 2012-2014, ARM Limited. All rights reserved.\r
+*\r
+*  This program and the accompanying materials\r
+*  are licensed and made available under the terms and conditions of the BSD License\r
+*  which accompanies this distribution.  The full text of the license may be found at\r
+*  http://opensource.org/licenses/bsd-license.php\r
+*\r
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+*\r
+**/\r
+\r
+#include <Protocol/SimpleFileSystem.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/DebugLib.h>\r
+\r
+#include "BootMonFsInternal.h"\r
+\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsReadFile (\r
+  IN EFI_FILE_PROTOCOL  *This,\r
+  IN OUT UINTN          *BufferSize,\r
+  OUT VOID              *Buffer\r
+  )\r
+{\r
+  BOOTMON_FS_INSTANCE   *Instance;\r
+  BOOTMON_FS_FILE       *File;\r
+  EFI_DISK_IO_PROTOCOL  *DiskIo;\r
+  EFI_BLOCK_IO_MEDIA    *Media;\r
+  UINT64                FileStart;\r
+  EFI_STATUS            Status;\r
+  UINTN                 RemainingFileSize;\r
+\r
+  // Ensure the file has been written in Flash before reading it.\r
+  // This keeps the code simple and avoids having to manage a non-flushed file.\r
+  BootMonFsFlushFile (This);\r
+\r
+  File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
+  if (File == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance = File->Instance;\r
+  DiskIo = Instance->DiskIo;\r
+  Media = Instance->Media;\r
+  FileStart = (Media->LowestAlignedLba + File->HwDescription.BlockStart) * Media->BlockSize;\r
+\r
+  if (File->Position >= File->HwDescription.Region[0].Size) {\r
+    // The entire file has been read\r
+    *BufferSize = 0;\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  // This driver assumes that the entire file is in region 0.\r
+  RemainingFileSize = File->HwDescription.Region[0].Size - File->Position;\r
+\r
+  // If read would go past end of file, truncate the read\r
+  if (*BufferSize > RemainingFileSize) {\r
+    *BufferSize = RemainingFileSize;\r
+  }\r
+\r
+  Status = DiskIo->ReadDisk (\r
+                    DiskIo,\r
+                    Media->MediaId,\r
+                    FileStart + File->Position,\r
+                    *BufferSize,\r
+                    Buffer\r
+                    );\r
+  if (EFI_ERROR (Status)) {\r
+    *BufferSize = 0;\r
+  }\r
+\r
+  File->Position += *BufferSize;\r
+\r
+  return Status;\r
+}\r
+\r
+// Inserts an entry into the write chain\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsWriteFile (\r
+  IN EFI_FILE_PROTOCOL  *This,\r
+  IN OUT UINTN          *BufferSize,\r
+  IN VOID               *Buffer\r
+  )\r
+{\r
+  BOOTMON_FS_FILE         *File;\r
+  BOOTMON_FS_FILE_REGION  *Region;\r
+\r
+  File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
+  if (File == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (!(File->OpenMode & EFI_FILE_MODE_WRITE)) {\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  // Allocate and initialize the memory region\r
+  Region = (BOOTMON_FS_FILE_REGION*)AllocateZeroPool (sizeof (BOOTMON_FS_FILE_REGION));\r
+  if (Region == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Region->Buffer  = AllocateCopyPool (*BufferSize, Buffer);\r
+  if (Region->Buffer == NULL) {\r
+    FreePool (Region);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Region->Size    = *BufferSize;\r
+\r
+  Region->Offset = File->Position;\r
+\r
+  InsertTailList (&File->RegionToFlushLink, &Region->Link);\r
+\r
+  File->Position += *BufferSize;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsSetPosition (\r
+  IN EFI_FILE_PROTOCOL  *This,\r
+  IN UINT64             Position\r
+  )\r
+{\r
+  BOOTMON_FS_FILE         *File;\r
+\r
+  File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
+\r
+  // UEFI Spec section 12.5:\r
+  // "Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to\r
+  //  be set to the end of the file."\r
+  if (Position == 0xFFFFFFFFFFFFFFFF) {\r
+    File->Position = BootMonFsGetImageLength (File);\r
+  } else {\r
+    // NB: Seeking past the end of the file is valid.\r
+    File->Position = Position;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsGetPosition (\r
+  IN  EFI_FILE_PROTOCOL *This,\r
+  OUT UINT64            *Position\r
+  ) {\r
+  BOOTMON_FS_FILE         *File;\r
+\r
+  File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
+\r
+  *Position = File->Position;\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsUnsupported.c b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsUnsupported.c
new file mode 100644 (file)
index 0000000..4ecc4ea
--- /dev/null
@@ -0,0 +1,37 @@
+/** @file\r
+*\r
+*  Copyright (c) 2012-2014, ARM Limited. All rights reserved.\r
+*\r
+*  This program and the accompanying materials\r
+*  are licensed and made available under the terms and conditions of the BSD License\r
+*  which accompanies this distribution.  The full text of the license may be found at\r
+*  http://opensource.org/licenses/bsd-license.php\r
+*\r
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+*\r
+**/\r
+\r
+#include "BootMonFsInternal.h"\r
+\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsSetPositionUnsupported (\r
+  IN EFI_FILE_PROTOCOL  *This,\r
+  IN UINT64             Position\r
+  )\r
+{\r
+  ASSERT(0);\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+EFIAPI\r
+EFI_STATUS\r
+BootMonFsGetPositionUnsupported (\r
+  IN EFI_FILE_PROTOCOL  *This,\r
+  OUT UINT64            *Position\r
+  )\r
+{\r
+  ASSERT(0);\r
+  return EFI_UNSUPPORTED;\r
+}\r