#/** @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
# 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
#\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
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
-# 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
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
-# 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
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
-# 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
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
#\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
#\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
#\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
--- /dev/null
+#/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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