From 4a6a1b0658a6a88167170e0a94f0e8350fcf4515 Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Thu, 12 Jun 2014 01:39:49 +0200 Subject: Import FatPkg source code / SVN r93 (RHEL only) The upstream edk2 repository contains prebuilt FAT driver binaries only, no FAT driver source code. This patch imports the source, from , at commit 8ff136aa (SVN r93). The source provides both PEI and DXE modules. We'll use only the DXE driver (the edk2 tree carries a binary only for the latter anyway). Notes wrt. the 3facc08 -> 9ece15a rebase: - upstream updated the FAT driver from SVN r84 (git ee85fec8) to SVN r86 (git 2355ea2c) in commit 709edd44, take it into account here. Notes about the 9ece15a -> c9e5618 rebase: - upstream updated the FAT driver from SVN r86 (git 2355ea2c) to SVN r93 (git 8ff136aa) in commit 720f553d, take it into account here. --- FatPkg/EnhancedFatDxe/ComponentName.c | 351 +++++++ FatPkg/EnhancedFatDxe/Data.c | 52 + FatPkg/EnhancedFatDxe/Debug.c | 76 ++ FatPkg/EnhancedFatDxe/Delete.c | 136 +++ FatPkg/EnhancedFatDxe/DirectoryCache.c | 234 +++++ FatPkg/EnhancedFatDxe/DirectoryManage.c | 1563 ++++++++++++++++++++++++++++++ FatPkg/EnhancedFatDxe/DiskCache.c | 540 +++++++++++ FatPkg/EnhancedFatDxe/Fat.c | 498 ++++++++++ FatPkg/EnhancedFatDxe/Fat.h | 1289 ++++++++++++++++++++++++ FatPkg/EnhancedFatDxe/Fat.inf | 121 +++ FatPkg/EnhancedFatDxe/Fat.uni | Bin 0 -> 5114 bytes FatPkg/EnhancedFatDxe/FatExtra.uni | Bin 0 -> 4258 bytes FatPkg/EnhancedFatDxe/FatFileSystem.h | 217 +++++ FatPkg/EnhancedFatDxe/FileName.c | 579 +++++++++++ FatPkg/EnhancedFatDxe/FileSpace.c | 814 ++++++++++++++++ FatPkg/EnhancedFatDxe/Flush.c | 536 ++++++++++ FatPkg/EnhancedFatDxe/Hash.c | 214 ++++ FatPkg/EnhancedFatDxe/Info.c | 619 ++++++++++++ FatPkg/EnhancedFatDxe/Init.c | 414 ++++++++ FatPkg/EnhancedFatDxe/Misc.c | 737 ++++++++++++++ FatPkg/EnhancedFatDxe/Open.c | 352 +++++++ FatPkg/EnhancedFatDxe/OpenVolume.c | 76 ++ FatPkg/EnhancedFatDxe/ReadWrite.c | 700 +++++++++++++ FatPkg/EnhancedFatDxe/UnicodeCollation.c | 279 ++++++ FatPkg/FatPei/FatLiteAccess.c | 523 ++++++++++ FatPkg/FatPei/FatLiteApi.c | 618 ++++++++++++ FatPkg/FatPei/FatLiteApi.h | 27 + FatPkg/FatPei/FatLiteFmt.h | 140 +++ FatPkg/FatPei/FatLiteLib.c | 361 +++++++ FatPkg/FatPei/FatLitePeim.h | 522 ++++++++++ FatPkg/FatPei/FatPei.inf | 103 ++ FatPkg/FatPei/FatPei.uni | Bin 0 -> 4620 bytes FatPkg/FatPei/FatPeiExtra.uni | Bin 0 -> 4274 bytes FatPkg/FatPei/Part.c | 462 +++++++++ FatPkg/FatPkg.dec | 53 + FatPkg/FatPkg.dsc | 114 +++ FatPkg/FatPkg.uni | Bin 0 -> 4918 bytes FatPkg/FatPkgExtra.uni | Bin 0 -> 4248 bytes FatPkg/License.txt | 40 + 39 files changed, 13360 insertions(+) create mode 100644 FatPkg/EnhancedFatDxe/ComponentName.c create mode 100644 FatPkg/EnhancedFatDxe/Data.c create mode 100644 FatPkg/EnhancedFatDxe/Debug.c create mode 100644 FatPkg/EnhancedFatDxe/Delete.c create mode 100644 FatPkg/EnhancedFatDxe/DirectoryCache.c create mode 100644 FatPkg/EnhancedFatDxe/DirectoryManage.c create mode 100644 FatPkg/EnhancedFatDxe/DiskCache.c create mode 100644 FatPkg/EnhancedFatDxe/Fat.c create mode 100644 FatPkg/EnhancedFatDxe/Fat.h create mode 100644 FatPkg/EnhancedFatDxe/Fat.inf create mode 100644 FatPkg/EnhancedFatDxe/Fat.uni create mode 100644 FatPkg/EnhancedFatDxe/FatExtra.uni create mode 100644 FatPkg/EnhancedFatDxe/FatFileSystem.h create mode 100644 FatPkg/EnhancedFatDxe/FileName.c create mode 100644 FatPkg/EnhancedFatDxe/FileSpace.c create mode 100644 FatPkg/EnhancedFatDxe/Flush.c create mode 100644 FatPkg/EnhancedFatDxe/Hash.c create mode 100644 FatPkg/EnhancedFatDxe/Info.c create mode 100644 FatPkg/EnhancedFatDxe/Init.c create mode 100644 FatPkg/EnhancedFatDxe/Misc.c create mode 100644 FatPkg/EnhancedFatDxe/Open.c create mode 100644 FatPkg/EnhancedFatDxe/OpenVolume.c create mode 100644 FatPkg/EnhancedFatDxe/ReadWrite.c create mode 100644 FatPkg/EnhancedFatDxe/UnicodeCollation.c create mode 100644 FatPkg/FatPei/FatLiteAccess.c create mode 100644 FatPkg/FatPei/FatLiteApi.c create mode 100644 FatPkg/FatPei/FatLiteApi.h create mode 100644 FatPkg/FatPei/FatLiteFmt.h create mode 100644 FatPkg/FatPei/FatLiteLib.c create mode 100644 FatPkg/FatPei/FatLitePeim.h create mode 100644 FatPkg/FatPei/FatPei.inf create mode 100644 FatPkg/FatPei/FatPei.uni create mode 100644 FatPkg/FatPei/FatPeiExtra.uni create mode 100644 FatPkg/FatPei/Part.c create mode 100644 FatPkg/FatPkg.dec create mode 100644 FatPkg/FatPkg.dsc create mode 100644 FatPkg/FatPkg.uni create mode 100644 FatPkg/FatPkgExtra.uni create mode 100644 FatPkg/License.txt diff --git a/FatPkg/EnhancedFatDxe/ComponentName.c b/FatPkg/EnhancedFatDxe/ComponentName.c new file mode 100644 index 0000000..6b8ec47 --- /dev/null +++ b/FatPkg/EnhancedFatDxe/ComponentName.c @@ -0,0 +1,351 @@ +/*++ + +Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the Software +License Agreement which accompanies this distribution. + + +Module Name: + + ComponentName.c + +Abstract: + +--*/ + +#include "Fat.h" + +// +// EFI Component Name Functions +// +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +FatComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +FatComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +// +// EFI Component Name Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gFatComponentName = { + FatComponentNameGetDriverName, + FatComponentNameGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gFatComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) FatComponentNameGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) FatComponentNameGetControllerName, + "en" +}; + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mFatDriverNameTable[] = { + { + "eng;en", + L"FAT File System Driver" + }, + { + NULL, + NULL + } +}; + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mFatControllerNameTable[] = { + { + "eng;en", + L"FAT File System" + }, + { + NULL, + NULL + } +}; + + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +FatComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mFatDriverNameTable, + DriverName, + (BOOLEAN)(This == &gFatComponentName) + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +FatComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + EFI_STATUS Status; + + // + // This is a device driver, so ChildHandle must be NULL. + // + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + // + // Make sure this driver is currently managing ControllHandle + // + Status = EfiTestManagedDevice ( + ControllerHandle, + gFatDriverBinding.DriverBindingHandle, + &gEfiDiskIoProtocolGuid + ); + if (EFI_ERROR (Status)) { + return Status; + } + + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mFatControllerNameTable, + ControllerName, + (BOOLEAN)(This == &gFatComponentName) + ); +} diff --git a/FatPkg/EnhancedFatDxe/Data.c b/FatPkg/EnhancedFatDxe/Data.c new file mode 100644 index 0000000..fd616c4 --- /dev/null +++ b/FatPkg/EnhancedFatDxe/Data.c @@ -0,0 +1,52 @@ +/*++ + +Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the Software +License Agreement which accompanies this distribution. + + +Module Name: + + Data.c + +Abstract: + + Global data in the FAT Filesystem driver + +Revision History + +--*/ + +#include "Fat.h" + +// +// Globals +// +// +// FatFsLock - Global lock for synchronizing all requests. +// +EFI_LOCK FatFsLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_CALLBACK); + +EFI_LOCK FatTaskLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY); + +// +// Filesystem interface functions +// +EFI_FILE_PROTOCOL FatFileInterface = { + EFI_FILE_PROTOCOL_REVISION, + FatOpen, + FatClose, + FatDelete, + FatRead, + FatWrite, + FatGetPosition, + FatSetPosition, + FatGetInfo, + FatSetInfo, + FatFlush, + FatOpenEx, + FatReadEx, + FatWriteEx, + FatFlushEx +}; diff --git a/FatPkg/EnhancedFatDxe/Debug.c b/FatPkg/EnhancedFatDxe/Debug.c new file mode 100644 index 0000000..29ec0bf --- /dev/null +++ b/FatPkg/EnhancedFatDxe/Debug.c @@ -0,0 +1,76 @@ +/*++ + +Copyright (c) 2005, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the Software +License Agreement which accompanies this distribution. + + +Module Name: + + debug.c + +Abstract: + + Debug functions for fat driver + +Revision History + +--*/ + +#include "Fat.h" + +VOID +FatDumpFatTable ( + IN FAT_VOLUME *Volume + ) +/*++ + +Routine Description: + + Dump all the FAT Entry of the FAT table in the volume + +Arguments: + + Volume - The volume whose FAT info will be dumped + +Returns: + + None + +--*/ +{ + UINTN EntryValue; + UINTN MaxIndex; + UINTN Index; + CHAR16 *Pointer; + + MaxIndex = Volume->MaxCluster + 2; + + Print (L"Dump of Fat Table, MaxCluster %x\n", MaxIndex); + for (Index = 0; Index < MaxIndex; Index++) { + EntryValue = FatGetFatEntry (Volume, Index); + if (EntryValue != FAT_CLUSTER_FREE) { + Pointer = NULL; + switch (EntryValue) { + case FAT_CLUSTER_RESERVED: + Pointer = L"RESREVED"; + break; + + case FAT_CLUSTER_BAD: + Pointer = L"BAD"; + break; + } + + if (FAT_END_OF_FAT_CHAIN (EntryValue)) { + Pointer = L"LAST"; + } + + if (Pointer != NULL) { + Print (L"Entry %x = %s\n", Index, Pointer); + } else { + Print (L"Entry %x = %x\n", Index, EntryValue); + } + } + } +} diff --git a/FatPkg/EnhancedFatDxe/Delete.c b/FatPkg/EnhancedFatDxe/Delete.c new file mode 100644 index 0000000..3becf8e --- /dev/null +++ b/FatPkg/EnhancedFatDxe/Delete.c @@ -0,0 +1,136 @@ +/*++ + +Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the Software +License Agreement which accompanies this distribution. + + +Module Name: + + delete.c + +Abstract: + + Function that deletes a file + +Revision History + +--*/ + +#include "Fat.h" + +EFI_STATUS +EFIAPI +FatDelete ( + IN EFI_FILE_PROTOCOL *FHand + ) +/*++ + +Routine Description: + + Deletes the file & Closes the file handle. + +Arguments: + + FHand - Handle to the file to delete. + +Returns: + + EFI_SUCCESS - Delete the file successfully. + EFI_WARN_DELETE_FAILURE - Fail to delete the file. + +--*/ +{ + FAT_IFILE *IFile; + FAT_OFILE *OFile; + FAT_DIRENT *DirEnt; + EFI_STATUS Status; + UINTN Round; + + IFile = IFILE_FROM_FHAND (FHand); + OFile = IFile->OFile; + + FatWaitNonblockingTask (IFile); + + // + // Lock the volume + // + FatAcquireLock (); + + // + // If the file is read-only, then don't delete it + // + if (IFile->ReadOnly) { + Status = EFI_WRITE_PROTECTED; + goto Done; + } + // + // If the file is the root dir, then don't delete it + // + if (OFile->Parent == NULL) { + Status = EFI_ACCESS_DENIED; + goto Done; + } + // + // If the file has a permanant error, skip the delete + // + Status = OFile->Error; + if (!EFI_ERROR (Status)) { + // + // If this is a directory, make sure it's empty before + // allowing it to be deleted + // + if (OFile->ODir != NULL) { + // + // We do not allow to delete nonempty directory + // + FatResetODirCursor (OFile); + for (Round = 0; Round < 3; Round++) { + Status = FatGetNextDirEnt (OFile, &DirEnt); + if ((EFI_ERROR (Status)) || + ((Round < 2) && (DirEnt == NULL || !FatIsDotDirEnt (DirEnt))) || + ((Round == 2) && (DirEnt != NULL)) + ) { + Status = EFI_ACCESS_DENIED; + goto Done; + } + } + } + // + // Return the file's space by setting its size to 0 + // + FatTruncateOFile (OFile, 0); + // + // Free the directory entry for this file + // + Status = FatRemoveDirEnt (OFile->Parent, OFile->DirEnt); + if (EFI_ERROR (Status)) { + goto Done; + } + // + // Set a permanent error for this OFile in case there + // are still opened IFiles attached + // + OFile->Error = EFI_NOT_FOUND; + } else if (OFile->Error == EFI_NOT_FOUND) { + Status = EFI_SUCCESS; + } + +Done: + // + // Always close the handle + // + FatIFileClose (IFile); + // + // Done + // + Status = FatCleanupVolume (OFile->Volume, NULL, Status, NULL); + FatReleaseLock (); + + if (EFI_ERROR (Status)) { + Status = EFI_WARN_DELETE_FAILURE; + } + + return Status; +} diff --git a/FatPkg/EnhancedFatDxe/DirectoryCache.c b/FatPkg/EnhancedFatDxe/DirectoryCache.c new file mode 100644 index 0000000..488ea22 --- /dev/null +++ b/FatPkg/EnhancedFatDxe/DirectoryCache.c @@ -0,0 +1,234 @@ +/*++ + +Copyright (c) 2005, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the Software +License Agreement which accompanies this distribution. + + +Module Name: + + DirectoryCache.c + +Abstract: + + Functions for directory cache operation + +Revision History + +--*/ + +#include "Fat.h" + +STATIC +VOID +FatFreeODir ( + IN FAT_ODIR *ODir + ) +/*++ + +Routine Description: + + Free the directory structure and release the memory. + +Arguments: + + ODir - The directory to be freed. + +Returns: + + None. + +--*/ +{ + FAT_DIRENT *DirEnt; + + // + // Release Directory Entry Nodes + // + while (!IsListEmpty (&ODir->ChildList)) { + DirEnt = DIRENT_FROM_LINK (ODir->ChildList.ForwardLink); + RemoveEntryList (&DirEnt->Link); + // + // Make sure the OFile has been closed + // + ASSERT (DirEnt->OFile == NULL); + FatFreeDirEnt (DirEnt); + } + + FreePool (ODir); +} + +STATIC +FAT_ODIR * +FatAllocateODir ( + IN FAT_OFILE *OFile + ) +/*++ + +Routine Description: + + Allocate the directory structure. + +Arguments: + + OFile - The corresponding OFile. + +Returns: + + None. + +--*/ +{ + FAT_ODIR *ODir; + + ODir = AllocateZeroPool (sizeof (FAT_ODIR)); + if (ODir != NULL) { + // + // Initialize the directory entry list + // + ODir->Signature = FAT_ODIR_SIGNATURE; + InitializeListHead (&ODir->ChildList); + ODir->CurrentCursor = &ODir->ChildList; + } + + return ODir; +} + +VOID +FatDiscardODir ( + IN FAT_OFILE *OFile + ) +/*++ + +Routine Description: + + Discard the directory structure when an OFile will be freed. + Volume will cache this directory if the OFile does not represent a deleted file. + +Arguments: + + OFile - The OFile whose directory structure is to be discarded. + +Returns: + + None. + +--*/ +{ + FAT_ODIR *ODir; + FAT_VOLUME *Volume; + + Volume = OFile->Volume; + ODir = OFile->ODir; + if (!OFile->DirEnt->Invalid) { + // + // If OFile does not represent a deleted file, then we will cache the directory + // We use OFile's first cluster as the directory's tag + // + ODir->DirCacheTag = OFile->FileCluster; + InsertHeadList (&Volume->DirCacheList, &ODir->DirCacheLink); + if (Volume->DirCacheCount == FAT_MAX_DIR_CACHE_COUNT) { + // + // Replace the least recent used directory + // + ODir = ODIR_FROM_DIRCACHELINK (Volume->DirCacheList.BackLink); + RemoveEntryList (&ODir->DirCacheLink); + } else { + // + // No need to find a replace + // + Volume->DirCacheCount++; + ODir = NULL; + } + } + // + // Release ODir Structure + // + if (ODir != NULL) { + FatFreeODir (ODir); + } +} + +VOID +FatRequestODir ( + IN FAT_OFILE *OFile + ) +/*++ + +Routine Description: + + Request the directory structure when an OFile is newly generated. + If the directory structure is cached by volume, then just return this directory; + Otherwise, allocate a new one for OFile. + +Arguments: + + OFile - The OFile which requests directory structure. + +Returns: + + None. + +--*/ +{ + UINTN DirCacheTag; + FAT_VOLUME *Volume; + FAT_ODIR *ODir; + FAT_ODIR *CurrentODir; + LIST_ENTRY *CurrentODirLink; + + Volume = OFile->Volume; + ODir = NULL; + DirCacheTag = OFile->FileCluster; + for (CurrentODirLink = Volume->DirCacheList.ForwardLink; + CurrentODirLink != &Volume->DirCacheList; + CurrentODirLink = CurrentODirLink->ForwardLink + ) { + CurrentODir = ODIR_FROM_DIRCACHELINK (CurrentODirLink); + if (CurrentODir->DirCacheTag == DirCacheTag) { + RemoveEntryList (&CurrentODir->DirCacheLink); + Volume->DirCacheCount--; + ODir = CurrentODir; + break; + } + } + + if (ODir == NULL) { + // + // This directory is not cached, then allocate a new one + // + ODir = FatAllocateODir (OFile); + } + + OFile->ODir = ODir; +} + +VOID +FatCleanupODirCache ( + IN FAT_VOLUME *Volume + ) +/*++ + +Routine Description: + + Clean up all the cached directory structures when the volume is going to be abandoned. + +Arguments: + + Volume - FAT file system volume. + +Returns: + + None. + +--*/ +{ + FAT_ODIR *ODir; + while (Volume->DirCacheCount > 0) { + ODir = ODIR_FROM_DIRCACHELINK (Volume->DirCacheList.BackLink); + RemoveEntryList (&ODir->DirCacheLink); + FatFreeODir (ODir); + Volume->DirCacheCount--; + } +} diff --git a/FatPkg/EnhancedFatDxe/DirectoryManage.c b/FatPkg/EnhancedFatDxe/DirectoryManage.c new file mode 100644 index 0000000..53e80f7 --- /dev/null +++ b/FatPkg/EnhancedFatDxe/DirectoryManage.c @@ -0,0 +1,1563 @@ +/*++ + +Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the Software +License Agreement which accompanies this distribution. + + +Module Name: + + DirectoryManage.c + +Abstract: + + Functions for performing directory entry io + +Revision History + +--*/ + +#include "Fat.h" + +STATIC +EFI_STATUS +FatAccessEntry ( + IN FAT_OFILE *Parent, + IN IO_MODE IoMode, + IN UINTN EntryPos, + IN OUT VOID *Entry + ) +/*++ + +Routine Description: + + Get a directory entry from disk for the Ofile. + +Arguments: + + Parent - The parent of the OFile which need to update. + IoMode - Indicate whether to read directory entry or write directroy entry. + EntryPos - The position of the directory entry to be accessed. + Entry - The directory entry read or written. + +Returns: + + EFI_SUCCESS - Access the directory entry sucessfully. + other - An error occurred when reading the directory entry. + +--*/ +{ + UINTN Position; + UINTN BufferSize; + + Position = EntryPos * sizeof (FAT_DIRECTORY_ENTRY); + if (Position >= Parent->FileSize) { + // + // End of directory + // + ASSERT (IoMode == READ_DATA); + ((FAT_DIRECTORY_ENTRY *) Entry)->FileName[0] = EMPTY_ENTRY_MARK; + ((FAT_DIRECTORY_ENTRY *) Entry)->Attributes = 0; + return EFI_SUCCESS; + } + + BufferSize = sizeof (FAT_DIRECTORY_ENTRY); + return FatAccessOFile (Parent, IoMode, Position, &BufferSize, Entry, NULL); +} + +EFI_STATUS +FatStoreDirEnt ( + IN FAT_OFILE *OFile, + IN FAT_DIRENT *DirEnt + ) +/*++ + +Routine Description: + + Save the directory entry to disk. + +Arguments: + + OFile - The parent OFile which needs to update. + DirEnt - The directory entry to be saved. + +Returns: + + EFI_SUCCESS - Store the directory entry successfully. + other - An error occurred when writing the directory entry. + +--*/ +{ + EFI_STATUS Status; + FAT_DIRECTORY_LFN LfnEntry; + UINTN EntryPos; + CHAR16 *LfnBufferPointer; + CHAR16 LfnBuffer[MAX_LFN_ENTRIES * LFN_CHAR_TOTAL + 1]; + UINT8 EntryCount; + UINT8 LfnOrdinal; + + EntryPos = DirEnt->EntryPos; + EntryCount = DirEnt->EntryCount; + // + // Write directory entry + // + Status = FatAccessEntry (OFile, WRITE_DATA, EntryPos, &DirEnt->Entry); + if (EFI_ERROR (Status)) { + return Status; + } + + if (--EntryCount > 0) { + // + // Write LFN directory entry + // + SetMem (LfnBuffer, sizeof (CHAR16) * LFN_CHAR_TOTAL * EntryCount, 0xff); + StrCpy (LfnBuffer, DirEnt->FileString); + LfnBufferPointer = LfnBuffer; + LfnEntry.Attributes = FAT_ATTRIBUTE_LFN; + LfnEntry.Type = 0; + LfnEntry.MustBeZero = 0; + LfnEntry.Checksum = FatCheckSum (DirEnt->Entry.FileName); + for (LfnOrdinal = 1; LfnOrdinal <= EntryCount; LfnOrdinal++) { + LfnEntry.Ordinal = LfnOrdinal; + if (LfnOrdinal == EntryCount) { + LfnEntry.Ordinal |= FAT_LFN_LAST; + } + + CopyMem (LfnEntry.Name1, LfnBufferPointer, sizeof (CHAR16) * LFN_CHAR1_LEN); + LfnBufferPointer += LFN_CHAR1_LEN; + CopyMem (LfnEntry.Name2, LfnBufferPointer, sizeof (CHAR16) * LFN_CHAR2_LEN); + LfnBufferPointer += LFN_CHAR2_LEN; + CopyMem (LfnEntry.Name3, LfnBufferPointer, sizeof (CHAR16) * LFN_CHAR3_LEN); + LfnBufferPointer += LFN_CHAR3_LEN; + EntryPos--; + if (DirEnt->Invalid) { + LfnEntry.Ordinal = DELETE_ENTRY_MARK; + } + + Status = FatAccessEntry (OFile, WRITE_DATA, EntryPos, &LfnEntry); + if (EFI_ERROR (Status)) { + return Status; + } + } + } + + return EFI_SUCCESS; +} + +BOOLEAN +FatIsDotDirEnt ( + IN FAT_DIRENT *DirEnt + ) +/*++ + +Routine Description: + + Determine whether the directory entry is "." or ".." entry. + +Arguments: + + DirEnt - The corresponding directory entry. + +Returns: + + TRUE - The directory entry is "." or ".." directory entry + FALSE - The directory entry is not "." or ".." directory entry + +--*/ +{ + CHAR16 *FileString; + FileString = DirEnt->FileString; + if (StrCmp (FileString, L".") == 0 || StrCmp (FileString, L"..") == 0) { + return TRUE; + } + + return FALSE; +} + +STATIC +VOID +FatSetDirEntCluster ( + IN FAT_OFILE *OFile + ) +/*++ + +Routine Description: + + Set the OFile's cluster info in its directory entry. + +Arguments: + + OFile - The corresponding OFile. + +Returns: + + None. + +--*/ +{ + UINTN Cluster; + FAT_DIRENT *DirEnt; + + DirEnt = OFile->DirEnt; + Cluster = OFile->FileCluster; + DirEnt->Entry.FileClusterHigh = (UINT16) (Cluster >> 16); + DirEnt->Entry.FileCluster = (UINT16) Cluster; +} + +VOID +FatUpdateDirEntClusterSizeInfo ( + IN FAT_OFILE *OFile + ) +/*++ + +Routine Description: + + Set the OFile's cluster and size info in its directory entry. + +Arguments: + + OFile - The corresponding OFile. + +Returns: + + None. + +--*/ +{ + ASSERT (OFile->ODir == NULL); + OFile->DirEnt->Entry.FileSize = (UINT32) OFile->FileSize; + FatSetDirEntCluster (OFile); +} + +VOID +FatCloneDirEnt ( + IN FAT_DIRENT *DirEnt1, + IN FAT_DIRENT *DirEnt2 + ) +/*++ + +Routine Description: + + Copy all the information of DirEnt2 to DirEnt1 except for 8.3 name. + +Arguments: + + DirEnt1 - The destination directory entry. + DirEnt2 - The source directory entry. + +Returns: + + None. + +--*/ +{ + UINT8 *Entry1; + UINT8 *Entry2; + Entry1 = (UINT8 *) &DirEnt1->Entry; + Entry2 = (UINT8 *) &DirEnt2->Entry; + CopyMem ( + Entry1 + FAT_ENTRY_INFO_OFFSET, + Entry2 + FAT_ENTRY_INFO_OFFSET, + sizeof (FAT_DIRECTORY_ENTRY) - FAT_ENTRY_INFO_OFFSET + ); +} + +STATIC +VOID +FatLoadLongNameEntry ( + IN FAT_OFILE *Parent, + IN FAT_DIRENT *DirEnt + ) +/*++ + +Routine Description: + + Get the LFN for the directory entry. + +Arguments: + + Parent - The parent directory. + DirEnt - The directory entry to get LFN. + +Returns: + + None. + +--*/ +{ + CHAR16 LfnBuffer[MAX_LFN_ENTRIES * LFN_CHAR_TOTAL + 1]; + CHAR16 *LfnBufferPointer; + CHAR8 *File8Dot3Name; + UINTN EntryPos; + UINT8 LfnOrdinal; + UINT8 LfnChecksum; + FAT_DIRECTORY_LFN LfnEntry; + EFI_STATUS Status; + + EntryPos = DirEnt->EntryPos; + File8Dot3Name = DirEnt->Entry.FileName; + LfnBufferPointer = LfnBuffer; + // + // Computes checksum for LFN + // + LfnChecksum = FatCheckSum (File8Dot3Name); + LfnOrdinal = 1; + do { + if (EntryPos == 0) { + LfnBufferPointer = LfnBuffer; + break; + } + + EntryPos--; + Status = FatAccessEntry (Parent, READ_DATA, EntryPos, &LfnEntry); + if (EFI_ERROR (Status) || + LfnEntry.Attributes != FAT_ATTRIBUTE_LFN || + LfnEntry.MustBeZero != 0 || + LfnEntry.Checksum != LfnChecksum || + (LfnEntry.Ordinal & (~FAT_LFN_LAST)) != LfnOrdinal || + LfnOrdinal > MAX_LFN_ENTRIES + ) { + // + // The directory entry does not have a long file name or + // some error occurs when loading long file name for a directory entry, + // and then we load the long name from short name + // + LfnBufferPointer = LfnBuffer; + break; + } + + CopyMem (LfnBufferPointer, LfnEntry.Name1, sizeof (CHAR16) * LFN_CHAR1_LEN); + LfnBufferPointer += LFN_CHAR1_LEN; + CopyMem (LfnBufferPointer, LfnEntry.Name2, sizeof (CHAR16) * LFN_CHAR2_LEN); + LfnBufferPointer += LFN_CHAR2_LEN; + CopyMem (LfnBufferPointer, LfnEntry.Name3, sizeof (CHAR16) * LFN_CHAR3_LEN); + LfnBufferPointer += LFN_CHAR3_LEN; + LfnOrdinal++; + } while ((LfnEntry.Ordinal & FAT_LFN_LAST) == 0); + DirEnt->EntryCount = LfnOrdinal; + // + // Terminate current Lfnbuffer + // + *LfnBufferPointer = 0; + if (LfnBufferPointer == LfnBuffer) { + // + // Fail to get the long file name from long file name entry, + // get the file name from short name + // + FatGetFileNameViaCaseFlag (DirEnt, LfnBuffer); + } + + DirEnt->FileString = AllocateCopyPool (StrSize (LfnBuffer), LfnBuffer); +} + +STATIC +VOID +FatAddDirEnt ( + IN FAT_ODIR *ODir, + IN FAT_DIRENT *DirEnt + ) +/*++ + +Routine Description: + + Add this directory entry node to the list of directory entries and hash table. + +Arguments: + + ODir - The parent OFile which needs to be updated. + DirEnt - The directory entry to be added. + +Returns: + + None. + +--*/ +{ + if (DirEnt->Link.BackLink == NULL) { + DirEnt->Link.BackLink = &ODir->ChildList; + } + InsertTailList (DirEnt->Link.BackLink, &DirEnt->Link); + FatInsertToHashTable (ODir, DirEnt); +} + +STATIC +EFI_STATUS +FatLoadNextDirEnt ( + IN FAT_OFILE *OFile, + OUT FAT_DIRENT **PtrDirEnt + ) +/*++ + +Routine Description: + + Load from disk the next directory entry at current end of directory position + +Arguments: + + OFile - The parent OFile. + PtrDirEnt - The directory entry that is loaded. + +Returns: + + EFI_SUCCESS - Load the directory entry successfully. + EFI_OUT_OF_RESOURCES - Out of resource. + other - An error occurred when reading the directory entries. + +--*/ +{ + EFI_STATUS Status; + FAT_DIRENT *DirEnt; + FAT_ODIR *ODir; + FAT_DIRECTORY_ENTRY Entry; + + ODir = OFile->ODir; + // + // Make sure the parent's directory has been opened + // + ASSERT (ODir != NULL); + // + // Assert we have not reached the end of directory + // + ASSERT (!ODir->EndOfDir); + DirEnt = NULL; + + for (;;) { + // + // Read the next directory entry until we find a valid directory entry (excluding lfn entry) + // + Status = FatAccessEntry (OFile, READ_DATA, ODir->CurrentEndPos, &Entry); + if (EFI_ERROR (Status)) { + return Status; + } + + if (((UINT8) Entry.FileName[0] != DELETE_ENTRY_MARK) && (Entry.Attributes & FAT_ATTRIBUTE_VOLUME_ID) == 0) { + // + // We get a valid directory entry, then handle it + // + break; + } + + ODir->CurrentEndPos++; + } + + if (Entry.FileName[0] != EMPTY_ENTRY_MARK) { + // + // Although FAT spec states this field is always 0 for FAT12 & FAT16, some applications + // might use it for some special usage, it is safer to zero it in memory for FAT12 & FAT16. + // + if (OFile->Volume->FatType != FAT32) { + Entry.FileClusterHigh = 0; + } + + // + // This is a valid directory entry + // + DirEnt = AllocateZeroPool (sizeof (FAT_DIRENT)); + if (DirEnt == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + DirEnt->Signature = FAT_DIRENT_SIGNATURE; + // + // Remember the directory's entry position on disk + // + DirEnt->EntryPos = (UINT16) ODir->CurrentEndPos; + CopyMem (&DirEnt->Entry, &Entry, sizeof (FAT_DIRECTORY_ENTRY)); + FatLoadLongNameEntry (OFile, DirEnt); + if (DirEnt->FileString == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + // + // Add this directory entry to directory + // + FatAddDirEnt (ODir, DirEnt); + // + // Point to next directory entry + // + ODir->CurrentEndPos++; + } else { + ODir->EndOfDir = TRUE; + } + + *PtrDirEnt = DirEnt; + return EFI_SUCCESS; + +Done: + FatFreeDirEnt (DirEnt); + return Status; +} + +EFI_STATUS +FatGetDirEntInfo ( + IN FAT_VOLUME *Volume, + IN FAT_DIRENT *DirEnt, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Get the directory entry's info into Buffer. + +Arguments: + + Volume - FAT file system volume. + DirEnt - The corresponding directory entry. + BufferSize - Size of Buffer. + Buffer - Buffer containing file info. + +Returns: + + EFI_SUCCESS - Get the file info successfully. + EFI_BUFFER_TOO_SMALL - The buffer is too small. + +--*/ +{ + UINTN Size; + UINTN NameSize; + UINTN ResultSize; + UINTN Cluster; + EFI_STATUS Status; + EFI_FILE_INFO *Info; + FAT_DIRECTORY_ENTRY *Entry; + FAT_DATE_TIME FatLastAccess; + + ASSERT_VOLUME_LOCKED (Volume); + + Size = SIZE_OF_EFI_FILE_INFO; + NameSize = StrSize (DirEnt->FileString); + ResultSize = Size + NameSize; + + Status = EFI_BUFFER_TOO_SMALL; + if (*BufferSize >= ResultSize) { + Status = EFI_SUCCESS; + Entry = &DirEnt->Entry; + Info = Buffer; + Info->Size = ResultSize; + if ((Entry->Attributes & FAT_ATTRIBUTE_DIRECTORY) != 0) { + Cluster = (Entry->FileClusterHigh << 16) | Entry->FileCluster; + Info->PhysicalSize = FatPhysicalDirSize (Volume, Cluster); + Info->FileSize = Info->PhysicalSize; + } else { + Info->FileSize = Entry->FileSize; + Info->PhysicalSize = FatPhysicalFileSize (Volume, Entry->FileSize); + } + + ZeroMem (&FatLastAccess.Time, sizeof (FatLastAccess.Time)); + CopyMem (&FatLastAccess.Date, &Entry->FileLastAccess, sizeof (FatLastAccess.Date)); + FatFatTimeToEfiTime (&FatLastAccess, &Info->LastAccessTime); + FatFatTimeToEfiTime (&Entry->FileCreateTime, &Info->CreateTime); + FatFatTimeToEfiTime (&Entry->FileModificationTime, &Info->ModificationTime); + Info->Attribute = Entry->Attributes & EFI_FILE_VALID_ATTR; + CopyMem ((CHAR8 *) Buffer + Size, DirEnt->FileString, NameSize); + } + + *BufferSize = ResultSize; + return Status; +} + +STATIC +EFI_STATUS +FatSearchODir ( + IN FAT_OFILE *OFile, + IN CHAR16 *FileNameString, + OUT FAT_DIRENT **PtrDirEnt + ) +/*++ + +Routine Description: + + Search the directory for the directory entry whose filename is FileNameString. + +Arguments: + + OFile - The parent OFile whose directory is to be searched. + FileNameString - The filename to be searched. + PtrDirEnt - pointer to the directory entry if found. + +Returns: + + EFI_SUCCESS - Find the directory entry or not found. + other - An error occurred when reading the directory entries. + +--*/ +{ + BOOLEAN PossibleShortName; + CHAR8 File8Dot3Name[FAT_NAME_LEN]; + FAT_ODIR *ODir; + FAT_DIRENT *DirEnt; + EFI_STATUS Status; + + ODir = OFile->ODir; + ASSERT (ODir != NULL); + // + // Check if the file name is a valid short name + // + PossibleShortName = FatCheckIs8Dot3Name (FileNameString, File8Dot3Name); + // + // Search the hash table first + // + DirEnt = *FatLongNameHashSearch (ODir, FileNameString); + if (DirEnt == NULL && PossibleShortName) { + DirEnt = *FatShortNameHashSearch (ODir, File8Dot3Name); + } + if (DirEnt == NULL) { + // + // We fail to get the directory entry from hash table; we then + // search the rest directory + // + while (!ODir->EndOfDir) { + Status = FatLoadNextDirEnt (OFile, &DirEnt); + if (EFI_ERROR (Status)) { + return Status; + } + + if (DirEnt != NULL) { + if (FatStriCmp (FileNameString, DirEnt->FileString) == 0) { + break; + } + + if (PossibleShortName && CompareMem (File8Dot3Name, DirEnt->Entry.FileName, FAT_NAME_LEN) == 0) { + break; + } + } + } + } + + *PtrDirEnt = DirEnt; + return EFI_SUCCESS; +} + +VOID +FatResetODirCursor ( + IN FAT_OFILE *OFile + ) +/*++ + +Routine Description: + + Set the OFile's current directory cursor to the list head. + +Arguments: + + OFile - The directory OFile whose directory cursor is reset. + +Returns: + + None. + +--*/ +{ + FAT_ODIR *ODir; + + ODir = OFile->ODir; + ASSERT (ODir != NULL); + ODir->CurrentCursor = &(ODir->ChildList); + ODir->CurrentPos = 0; +} + +EFI_STATUS +FatGetNextDirEnt ( + IN FAT_OFILE *OFile, + OUT FAT_DIRENT **PtrDirEnt + ) +/*++ + +Routine Description: + + Set the directory's cursor to the next and get the next directory entry. + +Arguments: + + OFile - The parent OFile. + PtrDirEnt - The next directory entry. + +Returns: + + EFI_SUCCESS - We get the next directory entry successfully. + other - An error occurred when get next directory entry. + +--*/ +{ + EFI_STATUS Status; + FAT_DIRENT *DirEnt; + FAT_ODIR *ODir; + + ODir = OFile->ODir; + ASSERT (ODir != NULL); + if (ODir->CurrentCursor->ForwardLink == &ODir->ChildList) { + // + // End of directory, we will try one more time + // + if (!ODir->EndOfDir) { + // + // Read directory from disk + // + Status = FatLoadNextDirEnt (OFile, &DirEnt); + if (EFI_ERROR (Status)) { + return Status; + } + } + } + + if (ODir->CurrentCursor->ForwardLink == &ODir->ChildList) { + // + // End of directory, return NULL + // + DirEnt = NULL; + ODir->CurrentPos = ODir->CurrentEndPos; + } else { + ODir->CurrentCursor = ODir->CurrentCursor->ForwardLink; + DirEnt = DIRENT_FROM_LINK (ODir->CurrentCursor); + ODir->CurrentPos = DirEnt->EntryPos + 1; + } + + *PtrDirEnt = DirEnt; + return EFI_SUCCESS; +} + +STATIC +VOID +FatSetEntryCount ( + IN FAT_OFILE *OFile, + IN FAT_DIRENT *DirEnt + ) +/*++ + +Routine Description: + + Set the directory entry count according to the filename. + +Arguments: + + OFile - The corresponding OFile. + DirEnt - The directory entry to be set. + +Returns: + + None. + +--*/ +{ + CHAR16 *FileString; + CHAR8 *File8Dot3Name; + + // + // Get new entry count and set the 8.3 name + // + DirEnt->EntryCount = 1; + FileString = DirEnt->FileString; + File8Dot3Name = DirEnt->Entry.FileName; + SetMem (File8Dot3Name, FAT_NAME_LEN, ' '); + if (StrCmp (FileString, L".") == 0) { + // + // "." entry + // + File8Dot3Name[0] = '.'; + FatCloneDirEnt (DirEnt, OFile->DirEnt); + } else if (StrCmp (FileString, L"..") == 0) { + // + // ".." entry + // + File8Dot3Name[0] = '.'; + File8Dot3Name[1] = '.'; + FatCloneDirEnt (DirEnt, OFile->Parent->DirEnt); + } else { + // + // Normal name + // + if (FatCheckIs8Dot3Name (FileString, File8Dot3Name)) { + // + // This file name is a valid 8.3 file name, we need to further check its case flag + // + FatSetCaseFlag (DirEnt); + } else { + // + // The file name is not a valid 8.3 name we need to generate an 8.3 name for it + // + FatCreate8Dot3Name (OFile, DirEnt); + DirEnt->EntryCount = (UINT8)(LFN_ENTRY_NUMBER (StrLen (FileString)) + DirEnt->EntryCount); + } + } +} + +STATIC +EFI_STATUS +FatExpandODir ( + IN FAT_OFILE *OFile + ) +/*++ + +Routine Description: + + Append a zero cluster to the current OFile. + +Arguments: + + OFile - The directory OFile which needs to be updated. + +Returns: + + EFI_SUCCESS - Append a zero cluster to the OFile successfully. + other - An error occurred when appending the zero cluster. + +--*/ +{ + return FatExpandOFile (OFile, OFile->FileSize + OFile->Volume->ClusterSize); +} + +STATIC +EFI_STATUS +FatSeekVolumeId ( + IN FAT_OFILE *Root, + OUT FAT_DIRENT *DirEnt + ) +/*++ + +Routine Description: + + Search the Root OFile for the possible volume label. + +Arguments: + + Root - The Root OFile. + DirEnt - The returned directory entry of volume label. + +Returns: + + EFI_SUCCESS - The search process is completed successfully. + other - An error occurred when searching volume label. + +--*/ +{ + EFI_STATUS Status; + UINTN EntryPos; + FAT_DIRECTORY_ENTRY *Entry; + + EntryPos = 0; + Entry = &DirEnt->Entry; + DirEnt->Invalid = TRUE; + do { + Status = FatAccessEntry (Root, READ_DATA, EntryPos, Entry); + if (EFI_ERROR (Status)) { + return Status; + } + + if (((UINT8) Entry->FileName[0] != DELETE_ENTRY_MARK) && (((Entry->Attributes) & (~FAT_ATTRIBUTE_ARCHIVE)) == FAT_ATTRIBUTE_VOLUME_ID)) { + DirEnt->EntryPos = (UINT16) EntryPos; + DirEnt->EntryCount = 1; + DirEnt->Invalid = FALSE; + break; + } + + EntryPos++; + } while (Entry->FileName[0] != EMPTY_ENTRY_MARK); + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +FatFirstFitInsertDirEnt ( + IN FAT_OFILE *OFile, + IN FAT_DIRENT *DirEnt + ) +/*++ + +Routine Description: + + Use First Fit Algorithm to insert directory entry. + Only this function will erase "E5" entries in a directory. + In view of safest recovery, this function will only be triggered + when maximum directory entry number has reached. + +Arguments: + + OFile - The corresponding OFile. + DirEnt - The directory entry to be inserted. + +Returns: + + EFI_SUCCESS - The directory entry has been successfully inserted. + EFI_VOLUME_FULL - The directory can not hold more directory entries. + Others - Some error occurred when inserting new directory entries. + +--*/ +{ + EFI_STATUS Status; + FAT_ODIR *ODir; + LIST_ENTRY *CurrentEntry; + FAT_DIRENT *CurrentDirEnt; + UINT32 CurrentPos; + UINT32 LabelPos; + UINT32 NewEntryPos; + UINT16 EntryCount; + FAT_DIRENT LabelDirEnt; + + LabelPos = 0; + if (OFile->Parent == NULL) { + Status = FatSeekVolumeId (OFile, &LabelDirEnt); + if (EFI_ERROR (Status)) { + return Status; + } + + if (!LabelDirEnt.Invalid) { + LabelPos = LabelDirEnt.EntryPos; + } + } + + EntryCount = DirEnt->EntryCount; + NewEntryPos = EntryCount; + CurrentPos = 0; + ODir = OFile->ODir; + for (CurrentEntry = ODir->ChildList.ForwardLink; + CurrentEntry != &ODir->ChildList; + CurrentEntry = CurrentEntry->ForwardLink + ) { + CurrentDirEnt = DIRENT_FROM_LINK (CurrentEntry); + if (NewEntryPos + CurrentDirEnt->EntryCount <= CurrentDirEnt->EntryPos) { + if (LabelPos > NewEntryPos || LabelPos <= CurrentPos) { + // + // first fit succeeded + // + goto Done; + } + } + + CurrentPos = CurrentDirEnt->EntryPos; + NewEntryPos = CurrentPos + EntryCount; + } + + if (NewEntryPos >= ODir->CurrentEndPos) { + return EFI_VOLUME_FULL; + } + +Done: + DirEnt->EntryPos = (UINT16) NewEntryPos; + DirEnt->Link.BackLink = CurrentEntry; + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +FatNewEntryPos ( + IN FAT_OFILE *OFile, + IN FAT_DIRENT *DirEnt + ) +/*++ + +Routine Description: + + Find the new directory entry position for the directory entry. + +Arguments: + + OFile - The corresponding OFile. + DirEnt - The directory entry whose new position is to be set. + +Returns: + + EFI_SUCCESS - The new directory entry position is successfully found. + EFI_VOLUME_FULL - The directory has reach its maximum capacity. + other - An error occurred when reading the directory entry. + +--*/ +{ + EFI_STATUS Status; + FAT_ODIR *ODir; + FAT_DIRENT *TempDirEnt; + UINT32 NewEndPos; + + ODir = OFile->ODir; + ASSERT (ODir != NULL); + // + // Make sure the whole directory has been loaded + // + while (!ODir->EndOfDir) { + Status = FatLoadNextDirEnt (OFile, &TempDirEnt); + if (EFI_ERROR (Status)) { + return Status; + } + } + // + // We will append this entry to the end of directory + // + FatGetCurrentFatTime (&DirEnt->Entry.FileCreateTime); + CopyMem (&DirEnt->Entry.FileModificationTime, &DirEnt->Entry.FileCreateTime, sizeof (FAT_DATE_TIME)); + CopyMem (&DirEnt->Entry.FileLastAccess, &DirEnt->Entry.FileCreateTime.Date, sizeof (FAT_DATE)); + NewEndPos = ODir->CurrentEndPos + DirEnt->EntryCount; + if (NewEndPos * sizeof (FAT_DIRECTORY_ENTRY) > OFile->FileSize) { + if (NewEndPos >= (OFile->IsFixedRootDir ? OFile->Volume->RootEntries : FAT_MAX_DIRENTRY_COUNT)) { + // + // We try to use fist fit algorithm to insert this directory entry + // + return FatFirstFitInsertDirEnt (OFile, DirEnt); + } + // + // We should allocate a new cluster for this directory + // + Status = FatExpandODir (OFile); + if (EFI_ERROR (Status)) { + return Status; + } + } + // + // We append our directory entry at the end of directory file + // + ODir->CurrentEndPos = NewEndPos; + DirEnt->EntryPos = (UINT16) (ODir->CurrentEndPos - 1); + return EFI_SUCCESS; +} + +EFI_STATUS +FatGetVolumeEntry ( + IN FAT_VOLUME *Volume, + IN CHAR16 *Name + ) +/*++ + +Routine Description: + + Get the directory entry for the volume. + +Arguments: + + Volume - FAT file system volume. + Name - The file name of the volume. + +Returns: + + EFI_SUCCESS - Update the volume with the directory entry sucessfully. + others - An error occurred when getting volume label. + +--*/ +{ + EFI_STATUS Status; + FAT_DIRENT LabelDirEnt; + + *Name = 0; + Status = FatSeekVolumeId (Volume->Root, &LabelDirEnt); + if (!EFI_ERROR (Status)) { + if (!LabelDirEnt.Invalid) { + FatNameToStr (LabelDirEnt.Entry.FileName, FAT_NAME_LEN, FALSE, Name); + } + } + + return Status; +} + +EFI_STATUS +FatSetVolumeEntry ( + IN FAT_VOLUME *Volume, + IN CHAR16 *Name + ) +/*++ + +Routine Description: + + Set the relevant directory entry into disk for the volume. + +Arguments: + + Volume - FAT file system volume. + Name - The new file name of the volume. + +Returns: + + EFI_SUCCESS - Update the Volume sucessfully. + EFI_UNSUPPORTED - The input label is not a valid volume label. + other - An error occurred when setting volume label. + +--*/ +{ + EFI_STATUS Status; + FAT_DIRENT LabelDirEnt; + FAT_OFILE *Root; + + Root = Volume->Root; + Status = FatSeekVolumeId (Volume->Root, &LabelDirEnt); + if (EFI_ERROR (Status)) { + return Status; + } + + if (LabelDirEnt.Invalid) { + // + // If there is not the relevant directory entry, create a new one + // + ZeroMem (&LabelDirEnt, sizeof (FAT_DIRENT)); + LabelDirEnt.EntryCount = 1; + Status = FatNewEntryPos (Root, &LabelDirEnt); + if (EFI_ERROR (Status)) { + return Status; + } + + LabelDirEnt.Entry.Attributes = FAT_ATTRIBUTE_VOLUME_ID; + } + + SetMem (LabelDirEnt.Entry.FileName, FAT_NAME_LEN, ' '); + if (FatStrToFat (Name, FAT_NAME_LEN, LabelDirEnt.Entry.FileName)) { + return EFI_UNSUPPORTED; + } + + FatGetCurrentFatTime (&LabelDirEnt.Entry.FileModificationTime); + return FatStoreDirEnt (Root, &LabelDirEnt); +} + +EFI_STATUS +FatCreateDotDirEnts ( + IN FAT_OFILE *OFile + ) +/*++ + +Routine Description: + + Create "." and ".." directory entries in the newly-created parent OFile. + +Arguments: + + OFile - The parent OFile. + +Returns: + + EFI_SUCCESS - The dot directory entries are successfully created. + other - An error occurred when creating the directory entry. + +--*/ +{ + EFI_STATUS Status; + FAT_DIRENT *DirEnt; + + Status = FatExpandODir (OFile); + if (EFI_ERROR (Status)) { + return Status; + } + + FatSetDirEntCluster (OFile); + // + // Create "." + // + Status = FatCreateDirEnt (OFile, L".", FAT_ATTRIBUTE_DIRECTORY, &DirEnt); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Create ".." + // + Status = FatCreateDirEnt (OFile, L"..", FAT_ATTRIBUTE_DIRECTORY, &DirEnt); + return Status; +} + +EFI_STATUS +FatCreateDirEnt ( + IN FAT_OFILE *OFile, + IN CHAR16 *FileName, + IN UINT8 Attributes, + OUT FAT_DIRENT **PtrDirEnt + ) +/*++ + +Routine Description: + + Create a directory entry in the parent OFile. + +Arguments: + + OFile - The parent OFile. + FileName - The filename of the newly-created directory entry. + Attributes - The attribute of the newly-created directory entry. + PtrDirEnt - The pointer to the newly-created directory entry. + +Returns: + + EFI_SUCCESS - The directory entry is successfully created. + EFI_OUT_OF_RESOURCES - Not enough memory to create the directory entry. + other - An error occurred when creating the directory entry. + +--*/ +{ + FAT_DIRENT *DirEnt; + FAT_ODIR *ODir; + EFI_STATUS Status; + + ASSERT (OFile != NULL); + ODir = OFile->ODir; + ASSERT (ODir != NULL); + DirEnt = AllocateZeroPool (sizeof (FAT_DIRENT)); + if (DirEnt == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + DirEnt->Signature = FAT_DIRENT_SIGNATURE; + DirEnt->FileString = AllocateCopyPool (StrSize (FileName), FileName); + if (DirEnt->FileString == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + // + // Determine how many directory entries we need + // + FatSetEntryCount (OFile, DirEnt); + // + // Determine the file's directory entry position + // + Status = FatNewEntryPos (OFile, DirEnt); + if (EFI_ERROR (Status)) { + goto Done; + } + + FatAddDirEnt (ODir, DirEnt); + DirEnt->Entry.Attributes = Attributes; + *PtrDirEnt = DirEnt; + DEBUG ((EFI_D_INFO, "FSOpen: Created new directory entry '%S'\n", DirEnt->FileString)); + return FatStoreDirEnt (OFile, DirEnt); + +Done: + FatFreeDirEnt (DirEnt); + return Status; +} + +EFI_STATUS +FatRemoveDirEnt ( + IN FAT_OFILE *OFile, + IN FAT_DIRENT *DirEnt + ) +/*++ + +Routine Description: + + Remove this directory entry node from the list of directory entries and hash table. + +Arguments: + + OFile - The parent OFile. + DirEnt - The directory entry to be removed. + +Returns: + + EFI_SUCCESS - The directory entry is successfully removed. + other - An error occurred when removing the directory entry. + +--*/ +{ + FAT_ODIR *ODir; + + ODir = OFile->ODir; + if (ODir->CurrentCursor == &DirEnt->Link) { + // + // Move the directory cursor to its previous directory entry + // + ODir->CurrentCursor = ODir->CurrentCursor->BackLink; + } + // + // Remove from directory entry list + // + RemoveEntryList (&DirEnt->Link); + // + // Remove from hash table + // + FatDeleteFromHashTable (ODir, DirEnt); + DirEnt->Entry.FileName[0] = DELETE_ENTRY_MARK; + DirEnt->Invalid = TRUE; + return FatStoreDirEnt (OFile, DirEnt); +} + +EFI_STATUS +FatOpenDirEnt ( + IN FAT_OFILE *Parent, + IN FAT_DIRENT *DirEnt + ) +/*++ + +Routine Description: + + Open the directory entry to get the OFile. + +Arguments: + + OFile - The parent OFile. + DirEnt - The directory entry to be opened. + +Returns: + + EFI_SUCCESS - The directory entry is successfully opened. + EFI_OUT_OF_RESOURCES - not enough memory to allocate a new OFile. + other - An error occurred when opening the directory entry. + +--*/ +{ + FAT_OFILE *OFile; + FAT_VOLUME *Volume; + + if (DirEnt->OFile == NULL) { + // + // Open the directory entry + // + OFile = AllocateZeroPool (sizeof (FAT_OFILE)); + if (OFile == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + OFile->Signature = FAT_OFILE_SIGNATURE; + InitializeListHead (&OFile->Opens); + InitializeListHead (&OFile->ChildHead); + OFile->Parent = Parent; + OFile->DirEnt = DirEnt; + if (Parent != NULL) { + // + // The newly created OFile is not root + // + Volume = Parent->Volume; + OFile->FullPathLen = Parent->FullPathLen + 1 + StrLen (DirEnt->FileString); + OFile->FileCluster = ((DirEnt->Entry.FileClusterHigh) << 16) | (DirEnt->Entry.FileCluster); + InsertTailList (&Parent->ChildHead, &OFile->ChildLink); + } else { + // + // The newly created OFile is root + // + Volume = VOLUME_FROM_ROOT_DIRENT (DirEnt); + Volume->Root = OFile; + OFile->FileCluster = Volume->RootCluster; + if (Volume->FatType != FAT32) { + OFile->IsFixedRootDir = TRUE; + } + } + + OFile->FileCurrentCluster = OFile->FileCluster; + OFile->Volume = Volume; + InsertHeadList (&Volume->CheckRef, &OFile->CheckLink); + + OFile->FileSize = DirEnt->Entry.FileSize; + if ((DirEnt->Entry.Attributes & FAT_ATTRIBUTE_DIRECTORY) != 0) { + if (OFile->IsFixedRootDir) { + OFile->FileSize = Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY); + } else { + OFile->FileSize = FatPhysicalDirSize (Volume, OFile->FileCluster); + } + + FatRequestODir (OFile); + if (OFile->ODir == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } + + DirEnt->OFile = OFile; + } + + return EFI_SUCCESS; +} + +VOID +FatCloseDirEnt ( + IN FAT_DIRENT *DirEnt + ) +/*++ + +Routine Description: + + Close the directory entry and free the OFile. + +Arguments: + + DirEnt - The directory entry to be closed. + +Returns: + + EFI_SUCCESS - The directory entry is successfully opened. + Other - An error occurred when opening the directory entry. + +--*/ +{ + FAT_OFILE *OFile; + FAT_VOLUME *Volume; + + OFile = DirEnt->OFile; + ASSERT (OFile != NULL); + Volume = OFile->Volume; + + if (OFile->ODir != NULL) { + FatDiscardODir (OFile); + } + + if (OFile->Parent == NULL) { + Volume->Root = NULL; + } else { + RemoveEntryList (&OFile->ChildLink); + } + + FreePool (OFile); + DirEnt->OFile = NULL; + if (DirEnt->Invalid == TRUE) { + // + // Free directory entry itself + // + FatFreeDirEnt (DirEnt); + } +} + +EFI_STATUS +FatLocateOFile ( + IN OUT FAT_OFILE **PtrOFile, + IN CHAR16 *FileName, + IN UINT8 Attributes, + OUT CHAR16 *NewFileName + ) +/*++ + +Routine Description: + + Traverse filename and open all OFiles that can be opened. + Update filename pointer to the component that can't be opened. + If more than one name component remains, returns an error; + otherwise, return the remaining name component so that the caller might choose to create it. + +Arguments: + PtrOFile - As input, the reference OFile; as output, the located OFile. + FileName - The file name relevant to the OFile. + Attributes - The attribute of the destination OFile. + NewFileName - The remaining file name. + +Returns: + + EFI_NOT_FOUND - The file name can't be opened and there is more than one + components within the name left (this means the name can + not be created either). + EFI_INVALID_PARAMETER - The parameter is not valid. + EFI_SUCCESS - Open the file successfully. + other - An error occured when locating the OFile. + +--*/ +{ + EFI_STATUS Status; + FAT_VOLUME *Volume; + CHAR16 ComponentName[EFI_PATH_STRING_LENGTH]; + UINTN FileNameLen; + BOOLEAN DirIntended; + CHAR16 *Next; + FAT_OFILE *OFile; + FAT_DIRENT *DirEnt; + + DirEnt = NULL; + + FileNameLen = StrLen (FileName); + if (FileNameLen == 0) { + return EFI_INVALID_PARAMETER; + } + + OFile = *PtrOFile; + Volume = OFile->Volume; + + DirIntended = FALSE; + if (FileName[FileNameLen - 1] == PATH_NAME_SEPARATOR) { + DirIntended = TRUE; + } + // + // If name starts with path name separator, then move to root OFile + // + if (*FileName == PATH_NAME_SEPARATOR) { + OFile = Volume->Root; + FileName++; + FileNameLen--; + } + // + // Per FAT Spec the file name should meet the following criteria: + // C1. Length (FileLongName) <= 255 + // C2. Length (X:FileFullPath) <= 260 + // Here we check C2 first. + // + if (2 + OFile->FullPathLen + 1 + FileNameLen + 1 > EFI_PATH_STRING_LENGTH) { + // + // Full path length can not surpass 256 + // + return EFI_INVALID_PARAMETER; + } + // + // Start at current location + // + Next = FileName; + for (;;) { + // + // Get the next component name + // + FileName = Next; + Next = FatGetNextNameComponent (FileName, ComponentName); + + // + // If end of the file name, we're done + // + if (ComponentName[0] == 0) { + if (DirIntended && OFile->ODir == NULL) { + return EFI_NOT_FOUND; + } + + NewFileName[0] = 0; + break; + } + // + // If "dot", then current + // + if (StrCmp (ComponentName, L".") == 0) { + continue; + } + // + // If "dot dot", then parent + // + if (StrCmp (ComponentName, L"..") == 0) { + if (OFile->Parent == NULL) { + return EFI_INVALID_PARAMETER; + } + OFile = OFile->Parent; + continue; + } + + if (!FatFileNameIsValid (ComponentName, NewFileName)) { + return EFI_INVALID_PARAMETER; + } + // + // We have a component name, try to open it + // + if (OFile->ODir == NULL) { + // + // This file isn't a directory, can't open it + // + return EFI_NOT_FOUND; + } + // + // Search the compName in the directory + // + Status = FatSearchODir (OFile, NewFileName, &DirEnt); + if (EFI_ERROR (Status)) { + return Status; + } + + if (DirEnt == NULL) { + // + // component name is not found in the directory + // + if (*Next != 0) { + return EFI_NOT_FOUND; + } + + if (DirIntended && (Attributes & FAT_ATTRIBUTE_DIRECTORY) == 0) { + return EFI_INVALID_PARAMETER; + } + // + // It's the last component name - return with the open + // path and the remaining name + // + break; + } + + Status = FatOpenDirEnt (OFile, DirEnt); + if (EFI_ERROR (Status)) { + return Status; + } + + OFile = DirEnt->OFile; + } + + *PtrOFile = OFile; + return EFI_SUCCESS; +} + diff --git a/FatPkg/EnhancedFatDxe/DiskCache.c b/FatPkg/EnhancedFatDxe/DiskCache.c new file mode 100644 index 0000000..fc116a9 --- /dev/null +++ b/FatPkg/EnhancedFatDxe/DiskCache.c @@ -0,0 +1,540 @@ +/*++ + +Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the Software +License Agreement which accompanies this distribution. + + +Module Name: + + DiskCache.c + +Abstract: + + Cache implementation for EFI FAT File system driver + +Revision History + +--*/ + +#include "Fat.h" + +STATIC +VOID +FatFlushDataCacheRange ( + IN FAT_VOLUME *Volume, + IN IO_MODE IoMode, + IN UINTN StartPageNo, + IN UINTN EndPageNo, + OUT UINT8 *Buffer + ) +/*++ + +Routine Description: + + This function is used by the Data Cache. + + When this function is called by write command, all entries in this range + are older than the contents in disk, so they are invalid; just mark them invalid. + + When this function is called by read command, if any entry in this range + is dirty, it means that the relative info directly readed from media is older than + than the info in the cache; So need to update the relative info in the Buffer. + +Arguments: + + Volume - FAT file system volume. + IoMode - This function is called by read command or write command + StartPageNo - First PageNo to be checked in the cache. + EndPageNo - Last PageNo to be checked in the cache. + Buffer - The user buffer need to update. Only when doing the read command + and there is dirty cache in the cache range, this parameter will be used. + +Returns: + + None. + +--*/ +{ + UINTN PageNo; + UINTN GroupNo; + UINTN GroupMask; + UINTN PageSize; + UINT8 PageAlignment; + DISK_CACHE *DiskCache; + CACHE_TAG *CacheTag; + UINT8 *BaseAddress; + + DiskCache = &Volume->DiskCache[CACHE_DATA]; + BaseAddress = DiskCache->CacheBase; + GroupMask = DiskCache->GroupMask; + PageAlignment = DiskCache->PageAlignment; + PageSize = (UINTN)1 << PageAlignment; + + for (PageNo = StartPageNo; PageNo < EndPageNo; PageNo++) { + GroupNo = PageNo & GroupMask; + CacheTag = &DiskCache->CacheTag[GroupNo]; + if (CacheTag->RealSize > 0 && CacheTag->PageNo == PageNo) { + // + // When reading data form disk directly, if some dirty data + // in cache is in this rang, this data in the Buffer need to + // be updated with the cache's dirty data. + // + if (IoMode == READ_DISK) { + if (CacheTag->Dirty) { + CopyMem ( + Buffer + ((PageNo - StartPageNo) << PageAlignment), + BaseAddress + (GroupNo << PageAlignment), + PageSize + ); + } + } else { + // + // Make all valid entries in this range invalid. + // + CacheTag->RealSize = 0; + } + } + } +} + +STATIC +EFI_STATUS +FatExchangeCachePage ( + IN FAT_VOLUME *Volume, + IN CACHE_DATA_TYPE DataType, + IN IO_MODE IoMode, + IN CACHE_TAG *CacheTag, + IN FAT_TASK *Task + ) +/*++ + +Routine Description: + + Exchange the cache page with the image on the disk + +Arguments: + + Volume - FAT file system volume. + DataType - Indicate the cache type. + IoMode - Indicate whether to load this page from disk or store this page to disk. + CacheTag - The Cache Tag for the current cache page. + +Returns: + + EFI_SUCCESS - Cache page exchanged successfully. + Others - An error occurred when exchanging cache page. + +--*/ +{ + EFI_STATUS Status; + UINTN GroupNo; + UINTN PageNo; + UINTN WriteCount; + UINTN RealSize; + UINT64 EntryPos; + UINT64 MaxSize; + DISK_CACHE *DiskCache; + VOID *PageAddress; + UINT8 PageAlignment; + + DiskCache = &Volume->DiskCache[DataType]; + PageNo = CacheTag->PageNo; + GroupNo = PageNo & DiskCache->GroupMask; + PageAlignment = DiskCache->PageAlignment; + PageAddress = DiskCache->CacheBase + (GroupNo << PageAlignment); + EntryPos = DiskCache->BaseAddress + LShiftU64 (PageNo, PageAlignment); + RealSize = CacheTag->RealSize; + if (IoMode == READ_DISK) { + RealSize = (UINTN)1 << PageAlignment; + MaxSize = DiskCache->LimitAddress - EntryPos; + if (MaxSize < RealSize) { + DEBUG ((EFI_D_INFO, "FatDiskIo: Cache Page OutBound occurred! \n")); + RealSize = (UINTN) MaxSize; + } + } + + WriteCount = 1; + if (DataType == CACHE_FAT && IoMode == WRITE_DISK) { + WriteCount = Volume->NumFats; + } + + do { + // + // Only fat table writing will execute more than once + // + Status = FatDiskIo (Volume, IoMode, EntryPos, RealSize, PageAddress, Task); + if (EFI_ERROR (Status)) { + return Status; + } + + EntryPos += Volume->FatSize; + } while (--WriteCount > 0); + + CacheTag->Dirty = FALSE; + CacheTag->RealSize = RealSize; + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +FatGetCachePage ( + IN FAT_VOLUME *Volume, + IN CACHE_DATA_TYPE CacheDataType, + IN UINTN PageNo, + IN CACHE_TAG *CacheTag + ) +/*++ + +Routine Description: + + Get one cache page by specified PageNo. + +Arguments: + + Volume - FAT file system volume. + CacheDataType - The cache type: CACHE_FAT or CACHE_DATA. + PageNo - PageNo to match with the cache. + CacheTag - The Cache Tag for the current cache page. + +Returns: + + EFI_SUCCESS - Get the cache page successfully. + other - An error occurred when accessing data. + +--*/ +{ + EFI_STATUS Status; + UINTN OldPageNo; + + OldPageNo = CacheTag->PageNo; + if (CacheTag->RealSize > 0 && OldPageNo == PageNo) { + // + // Cache Hit occurred + // + return EFI_SUCCESS; + } + + // + // Write dirty cache page back to disk + // + if (CacheTag->RealSize > 0 && CacheTag->Dirty) { + Status = FatExchangeCachePage (Volume, CacheDataType, WRITE_DISK, CacheTag, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + } + // + // Load new data from disk; + // + CacheTag->PageNo = PageNo; + Status = FatExchangeCachePage (Volume, CacheDataType, READ_DISK, CacheTag, NULL); + + return Status; +} + +STATIC +EFI_STATUS +FatAccessUnalignedCachePage ( + IN FAT_VOLUME *Volume, + IN CACHE_DATA_TYPE CacheDataType, + IN IO_MODE IoMode, + IN UINTN PageNo, + IN UINTN Offset, + IN UINTN Length, + IN OUT VOID *Buffer + ) +/*++ +Routine Description: + + Read Length bytes from the position of Offset into Buffer, or + write Length bytes from Buffer into the position of Offset. + +Arguments: + + Volume - FAT file system volume. + CacheDataType - The type of cache: CACHE_DATA or CACHE_FAT. + IoMode - Indicate the type of disk access. + PageNo - The number of unaligned cache page. + Offset - The starting byte of cache page. + Length - The number of bytes that is read or written + Buffer - Buffer containing cache data. + +Returns: + + EFI_SUCCESS - The data was accessed correctly. + Others - An error occurred when accessing unaligned cache page. + +--*/ +{ + EFI_STATUS Status; + VOID *Source; + VOID *Destination; + DISK_CACHE *DiskCache; + CACHE_TAG *CacheTag; + UINTN GroupNo; + + DiskCache = &Volume->DiskCache[CacheDataType]; + GroupNo = PageNo & DiskCache->GroupMask; + CacheTag = &DiskCache->CacheTag[GroupNo]; + Status = FatGetCachePage (Volume, CacheDataType, PageNo, CacheTag); + if (!EFI_ERROR (Status)) { + Source = DiskCache->CacheBase + (GroupNo << DiskCache->PageAlignment) + Offset; + Destination = Buffer; + if (IoMode != READ_DISK) { + CacheTag->Dirty = TRUE; + DiskCache->Dirty = TRUE; + Destination = Source; + Source = Buffer; + } + + CopyMem (Destination, Source, Length); + } + + return Status; +} + +EFI_STATUS +FatAccessCache ( + IN FAT_VOLUME *Volume, + IN CACHE_DATA_TYPE CacheDataType, + IN IO_MODE IoMode, + IN UINT64 Offset, + IN UINTN BufferSize, + IN OUT UINT8 *Buffer, + IN FAT_TASK *Task + ) +/*++ +Routine Description: + + Read BufferSize bytes from the position of Offset into Buffer, + or write BufferSize bytes from Buffer into the position of Offset. + + Base on the parameter of CACHE_DATA_TYPE, the data access will be divided into + the access of FAT cache (CACHE_FAT) and the access of Data cache (CACHE_DATA): + + 1. Access of FAT cache (CACHE_FAT): Access the data in the FAT cache, if there is cache + page hit, just return the cache page; else update the related cache page and return + the right cache page. + 2. Access of Data cache (CACHE_DATA): + The access data will be divided into UnderRun data, Aligned data and OverRun data; + The UnderRun data and OverRun data will be accessed by the Data cache, + but the Aligned data will be accessed with disk directly. + +Arguments: + + Volume - FAT file system volume. + CacheDataType - The type of cache: CACHE_DATA or CACHE_FAT. + IoMode - Indicate the type of disk access. + Offset - The starting byte offset to read from. + BufferSize - Size of Buffer. + Buffer - Buffer containing cache data. + +Returns: + + EFI_SUCCESS - The data was accessed correctly. + EFI_MEDIA_CHANGED - The MediaId does not match the current device. + Others - An error occurred when accessing cache. + +--*/ +{ + EFI_STATUS Status; + UINTN PageSize; + UINTN UnderRun; + UINTN OverRun; + UINTN AlignedSize; + UINTN Length; + UINTN PageNo; + UINTN AlignedPageCount; + UINTN OverRunPageNo; + DISK_CACHE *DiskCache; + UINT64 EntryPos; + UINT8 PageAlignment; + + ASSERT (Volume->CacheBuffer != NULL); + + Status = EFI_SUCCESS; + DiskCache = &Volume->DiskCache[CacheDataType]; + EntryPos = Offset - DiskCache->BaseAddress; + PageAlignment = DiskCache->PageAlignment; + PageSize = (UINTN)1 << PageAlignment; + PageNo = (UINTN) RShiftU64 (EntryPos, PageAlignment); + UnderRun = ((UINTN) EntryPos) & (PageSize - 1); + + if (UnderRun > 0) { + Length = PageSize - UnderRun; + if (Length > BufferSize) { + Length = BufferSize; + } + + Status = FatAccessUnalignedCachePage (Volume, CacheDataType, IoMode, PageNo, UnderRun, Length, Buffer); + if (EFI_ERROR (Status)) { + return Status; + } + + Buffer += Length; + BufferSize -= Length; + PageNo++; + } + + AlignedPageCount = BufferSize >> PageAlignment; + OverRunPageNo = PageNo + AlignedPageCount; + // + // The access of the Aligned data + // + if (AlignedPageCount > 0) { + // + // Accessing fat table cannot have alignment data + // + ASSERT (CacheDataType == CACHE_DATA); + + EntryPos = Volume->RootPos + LShiftU64 (PageNo, PageAlignment); + AlignedSize = AlignedPageCount << PageAlignment; + Status = FatDiskIo (Volume, IoMode, EntryPos, AlignedSize, Buffer, Task); + if (EFI_ERROR (Status)) { + return Status; + } + // + // If these access data over laps the relative cache range, these cache pages need + // to be updated. + // + FatFlushDataCacheRange (Volume, IoMode, PageNo, OverRunPageNo, Buffer); + Buffer += AlignedSize; + BufferSize -= AlignedSize; + } + // + // The access of the OverRun data + // + OverRun = BufferSize; + if (OverRun > 0) { + // + // Last read is not a complete page + // + Status = FatAccessUnalignedCachePage (Volume, CacheDataType, IoMode, OverRunPageNo, 0, OverRun, Buffer); + } + + return Status; +} + +EFI_STATUS +FatVolumeFlushCache ( + IN FAT_VOLUME *Volume, + IN FAT_TASK *Task + ) +/*++ + +Routine Description: + + Flush all the dirty cache back, include the FAT cache and the Data cache. + +Arguments: + + Volume - FAT file system volume. + +Returns: + + EFI_SUCCESS - Flush all the dirty cache back successfully + other - An error occurred when writing the data into the disk + +--*/ +{ + EFI_STATUS Status; + CACHE_DATA_TYPE CacheDataType; + UINTN GroupIndex; + UINTN GroupMask; + DISK_CACHE *DiskCache; + CACHE_TAG *CacheTag; + + for (CacheDataType = (CACHE_DATA_TYPE) 0; CacheDataType < CACHE_MAX_TYPE; CacheDataType++) { + DiskCache = &Volume->DiskCache[CacheDataType]; + if (DiskCache->Dirty) { + // + // Data cache or fat cache is dirty, write the dirty data back + // + GroupMask = DiskCache->GroupMask; + for (GroupIndex = 0; GroupIndex <= GroupMask; GroupIndex++) { + CacheTag = &DiskCache->CacheTag[GroupIndex]; + if (CacheTag->RealSize > 0 && CacheTag->Dirty) { + // + // Write back all Dirty Data Cache Page to disk + // + Status = FatExchangeCachePage (Volume, CacheDataType, WRITE_DISK, CacheTag, Task); + if (EFI_ERROR (Status)) { + return Status; + } + } + } + + DiskCache->Dirty = FALSE; + } + } + // + // Flush the block device. + // + Status = Volume->BlockIo->FlushBlocks (Volume->BlockIo); + return Status; +} + +EFI_STATUS +FatInitializeDiskCache ( + IN FAT_VOLUME *Volume + ) +/*++ + +Routine Description: + + Initialize the disk cache according to Volume's FatType. + +Arguments: + + Volume - FAT file system volume. + +Returns: + + EFI_SUCCESS - The disk cache is successfully initialized. + EFI_OUT_OF_RESOURCES - Not enough memory to allocate disk cache. + +--*/ +{ + DISK_CACHE *DiskCache; + UINTN FatCacheGroupCount; + UINTN DataCacheSize; + UINTN FatCacheSize; + UINT8 *CacheBuffer; + + DiskCache = Volume->DiskCache; + // + // Configure the parameters of disk cache + // + if (Volume->FatType == FAT12) { + FatCacheGroupCount = FAT_FATCACHE_GROUP_MIN_COUNT; + DiskCache[CACHE_FAT].PageAlignment = FAT_FATCACHE_PAGE_MIN_ALIGNMENT; + DiskCache[CACHE_DATA].PageAlignment = FAT_DATACACHE_PAGE_MIN_ALIGNMENT; + } else { + FatCacheGroupCount = FAT_FATCACHE_GROUP_MAX_COUNT; + DiskCache[CACHE_FAT].PageAlignment = FAT_FATCACHE_PAGE_MAX_ALIGNMENT; + DiskCache[CACHE_DATA].PageAlignment = FAT_DATACACHE_PAGE_MAX_ALIGNMENT; + } + + DiskCache[CACHE_DATA].GroupMask = FAT_DATACACHE_GROUP_COUNT - 1; + DiskCache[CACHE_DATA].BaseAddress = Volume->RootPos; + DiskCache[CACHE_DATA].LimitAddress = Volume->VolumeSize; + DiskCache[CACHE_FAT].GroupMask = FatCacheGroupCount - 1; + DiskCache[CACHE_FAT].BaseAddress = Volume->FatPos; + DiskCache[CACHE_FAT].LimitAddress = Volume->FatPos + Volume->FatSize; + FatCacheSize = FatCacheGroupCount << DiskCache[CACHE_FAT].PageAlignment; + DataCacheSize = FAT_DATACACHE_GROUP_COUNT << DiskCache[CACHE_DATA].PageAlignment; + // + // Allocate the Fat Cache buffer + // + CacheBuffer = AllocateZeroPool (FatCacheSize + DataCacheSize); + if (CacheBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Volume->CacheBuffer = CacheBuffer; + DiskCache[CACHE_FAT].CacheBase = CacheBuffer; + DiskCache[CACHE_DATA].CacheBase = CacheBuffer + FatCacheSize; + return EFI_SUCCESS; +} diff --git a/FatPkg/EnhancedFatDxe/Fat.c b/FatPkg/EnhancedFatDxe/Fat.c new file mode 100644 index 0000000..c78840a --- /dev/null +++ b/FatPkg/EnhancedFatDxe/Fat.c @@ -0,0 +1,498 @@ +/*++ + +Copyright (c) 2005 - 2014, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the Software +License Agreement which accompanies this distribution. + + +Module Name: + + Fat.c + +Abstract: + + Fat File System driver routines that support EFI driver model + +--*/ + +#include "Fat.h" + +EFI_STATUS +EFIAPI +FatEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +EFI_STATUS +EFIAPI +FatUnload ( + IN EFI_HANDLE ImageHandle + ); + +EFI_STATUS +EFIAPI +FatDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +FatDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +FatDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +// +// DriverBinding protocol instance +// +EFI_DRIVER_BINDING_PROTOCOL gFatDriverBinding = { + FatDriverBindingSupported, + FatDriverBindingStart, + FatDriverBindingStop, + 0xa, + NULL, + NULL +}; + +EFI_STATUS +EFIAPI +FatEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Register Driver Binding protocol for this driver. + +Arguments: + + ImageHandle - Handle for the image of this driver. + SystemTable - Pointer to the EFI System Table. + +Returns: + + EFI_SUCCESS - Driver loaded. + other - Driver not loaded. + +--*/ +{ + EFI_STATUS Status; + + // + // Initialize the EFI Driver Library + // + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gFatDriverBinding, + ImageHandle, + &gFatComponentName, + &gFatComponentName2 + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +EFI_STATUS +EFIAPI +FatUnload ( + IN EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + + Unload function for this image. Uninstall DriverBinding protocol. + +Arguments: + + ImageHandle - Handle for the image of this driver. + +Returns: + + EFI_SUCCESS - Driver unloaded successfully. + other - Driver can not unloaded. + +--*/ +{ + EFI_STATUS Status; + EFI_HANDLE *DeviceHandleBuffer; + UINTN DeviceHandleCount; + UINTN Index; + VOID *ComponentName; + VOID *ComponentName2; + + Status = gBS->LocateHandleBuffer ( + AllHandles, + NULL, + NULL, + &DeviceHandleCount, + &DeviceHandleBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + for (Index = 0; Index < DeviceHandleCount; Index++) { + Status = EfiTestManagedDevice (DeviceHandleBuffer[Index], ImageHandle, &gEfiDiskIoProtocolGuid); + if (!EFI_ERROR (Status)) { + Status = gBS->DisconnectController ( + DeviceHandleBuffer[Index], + ImageHandle, + NULL + ); + if (EFI_ERROR (Status)) { + break; + } + } + } + + if (Index == DeviceHandleCount) { + // + // Driver is stopped successfully. + // + Status = gBS->HandleProtocol (ImageHandle, &gEfiComponentNameProtocolGuid, &ComponentName); + if (EFI_ERROR (Status)) { + ComponentName = NULL; + } + + Status = gBS->HandleProtocol (ImageHandle, &gEfiComponentName2ProtocolGuid, &ComponentName2); + if (EFI_ERROR (Status)) { + ComponentName2 = NULL; + } + + if (ComponentName == NULL) { + if (ComponentName2 == NULL) { + Status = gBS->UninstallMultipleProtocolInterfaces ( + ImageHandle, + &gEfiDriverBindingProtocolGuid, &gFatDriverBinding, + NULL + ); + } else { + Status = gBS->UninstallMultipleProtocolInterfaces ( + ImageHandle, + &gEfiDriverBindingProtocolGuid, &gFatDriverBinding, + &gEfiComponentName2ProtocolGuid, ComponentName2, + NULL + ); + } + } else { + if (ComponentName2 == NULL) { + Status = gBS->UninstallMultipleProtocolInterfaces ( + ImageHandle, + &gEfiDriverBindingProtocolGuid, &gFatDriverBinding, + &gEfiComponentNameProtocolGuid, ComponentName, + NULL + ); + } else { + Status = gBS->UninstallMultipleProtocolInterfaces ( + ImageHandle, + &gEfiDriverBindingProtocolGuid, &gFatDriverBinding, + &gEfiComponentNameProtocolGuid, ComponentName, + &gEfiComponentName2ProtocolGuid, ComponentName2, + NULL + ); + } + } + } + + if (DeviceHandleBuffer != NULL) { + FreePool (DeviceHandleBuffer); + } + + return Status; +} + +EFI_STATUS +EFIAPI +FatDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + Test to see if this driver can add a file system to ControllerHandle. + ControllerHandle must support both Disk IO and Block IO protocols. + +Arguments: + + This - Protocol instance pointer. + ControllerHandle - Handle of device to test. + RemainingDevicePath - Not used. + +Returns: + + EFI_SUCCESS - This driver supports this device. + EFI_ALREADY_STARTED - This driver is already running on this device. + other - This driver does not support this device. + +--*/ +{ + EFI_STATUS Status; + EFI_DISK_IO_PROTOCOL *DiskIo; + + // + // Open the IO Abstraction(s) needed to perform the supported test + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiDiskIoProtocolGuid, + (VOID **) &DiskIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status)) { + return Status; + } + // + // Close the I/O Abstraction(s) used to perform the supported test + // + gBS->CloseProtocol ( + ControllerHandle, + &gEfiDiskIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + // + // Open the IO Abstraction(s) needed to perform the supported test + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiBlockIoProtocolGuid, + NULL, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + + return Status; +} + +EFI_STATUS +EFIAPI +FatDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + Start this driver on ControllerHandle by opening a Block IO and Disk IO + protocol, reading Device Path. Add a Simple File System protocol to + ControllerHandle if the media contains a valid file system. + +Arguments: + + This - Protocol instance pointer. + ControllerHandle - Handle of device to bind driver to. + RemainingDevicePath - Not used. + +Returns: + + EFI_SUCCESS - This driver is added to DeviceHandle. + EFI_ALREADY_STARTED - This driver is already running on DeviceHandle. + EFI_OUT_OF_RESOURCES - Can not allocate the memory. + other - This driver does not support this device. + +--*/ +{ + EFI_STATUS Status; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + EFI_DISK_IO_PROTOCOL *DiskIo; + EFI_DISK_IO2_PROTOCOL *DiskIo2; + BOOLEAN LockedByMe; + + LockedByMe = FALSE; + // + // Acquire the lock. + // If caller has already acquired the lock, cannot lock it again. + // + Status = FatAcquireLockOrFail (); + if (!EFI_ERROR (Status)) { + LockedByMe = TRUE; + } + + Status = InitializeUnicodeCollationSupport (This->DriverBindingHandle); + if (EFI_ERROR (Status)) { + goto Exit; + } + // + // Open our required BlockIo and DiskIo + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiBlockIoProtocolGuid, + (VOID **) &BlockIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiDiskIoProtocolGuid, + (VOID **) &DiskIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiDiskIo2ProtocolGuid, + (VOID **) &DiskIo2, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + DiskIo2 = NULL; + } + + // + // Allocate Volume structure. In FatAllocateVolume(), Resources + // are allocated with protocol installed and cached initialized + // + Status = FatAllocateVolume (ControllerHandle, DiskIo, DiskIo2, BlockIo); + + // + // When the media changes on a device it will Reinstall the BlockIo interaface. + // This will cause a call to our Stop(), and a subsequent reentrant call to our + // Start() successfully. We should leave the device open when this happen. + // + if (EFI_ERROR (Status)) { + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiSimpleFileSystemProtocolGuid, + NULL, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiDiskIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + gBS->CloseProtocol ( + ControllerHandle, + &gEfiDiskIo2ProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + } + } + +Exit: + // + // Unlock if locked by myself. + // + if (LockedByMe) { + FatReleaseLock (); + } + return Status; +} + +EFI_STATUS +EFIAPI +FatDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + +Routine Description: + Stop this driver on ControllerHandle. + +Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to stop driver on. + NumberOfChildren - Not used. + ChildHandleBuffer - Not used. + +Returns: + EFI_SUCCESS - This driver is removed DeviceHandle. + other - This driver was not removed from this device. + +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem; + FAT_VOLUME *Volume; + EFI_DISK_IO2_PROTOCOL *DiskIo2; + + DiskIo2 = NULL; + // + // Get our context back + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiSimpleFileSystemProtocolGuid, + (VOID **) &FileSystem, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (!EFI_ERROR (Status)) { + Volume = VOLUME_FROM_VOL_INTERFACE (FileSystem); + DiskIo2 = Volume->DiskIo2; + Status = FatAbandonVolume (Volume); + } + + if (!EFI_ERROR (Status)) { + if (DiskIo2 != NULL) { + Status = gBS->CloseProtocol ( + ControllerHandle, + &gEfiDiskIo2ProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + ASSERT_EFI_ERROR (Status); + } + Status = gBS->CloseProtocol ( + ControllerHandle, + &gEfiDiskIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + ASSERT_EFI_ERROR (Status); + } + + return Status; +} diff --git a/FatPkg/EnhancedFatDxe/Fat.h b/FatPkg/EnhancedFatDxe/Fat.h new file mode 100644 index 0000000..7a3cd06 --- /dev/null +++ b/FatPkg/EnhancedFatDxe/Fat.h @@ -0,0 +1,1289 @@ +/*++ + +Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the Software +License Agreement which accompanies this distribution. + + +Module Name: + + Fat.h + +Abstract: + + Main header file for EFI FAT file system driver + +Revision History + +--*/ + +#ifndef _FAT_H_ +#define _FAT_H_ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "FatFileSystem.h" + +// +// The FAT signature +// +#define FAT_VOLUME_SIGNATURE SIGNATURE_32 ('f', 'a', 't', 'v') +#define FAT_IFILE_SIGNATURE SIGNATURE_32 ('f', 'a', 't', 'i') +#define FAT_ODIR_SIGNATURE SIGNATURE_32 ('f', 'a', 't', 'd') +#define FAT_DIRENT_SIGNATURE SIGNATURE_32 ('f', 'a', 't', 'e') +#define FAT_OFILE_SIGNATURE SIGNATURE_32 ('f', 'a', 't', 'o') +#define FAT_TASK_SIGNATURE SIGNATURE_32 ('f', 'a', 't', 'T') +#define FAT_SUBTASK_SIGNATURE SIGNATURE_32 ('f', 'a', 't', 'S') + +#define ASSERT_VOLUME_LOCKED(a) ASSERT_LOCKED (&FatFsLock) + +#define IFILE_FROM_FHAND(a) CR (a, FAT_IFILE, Handle, FAT_IFILE_SIGNATURE) + +#define DIRENT_FROM_LINK(a) CR (a, FAT_DIRENT, Link, FAT_DIRENT_SIGNATURE) + +#define VOLUME_FROM_ROOT_DIRENT(a) CR (a, FAT_VOLUME, RootDirEnt, FAT_VOLUME_SIGNATURE) + +#define VOLUME_FROM_VOL_INTERFACE(a) CR (a, FAT_VOLUME, VolumeInterface, FAT_VOLUME_SIGNATURE); + +#define ODIR_FROM_DIRCACHELINK(a) CR (a, FAT_ODIR, DirCacheLink, FAT_ODIR_SIGNATURE) + +#define OFILE_FROM_CHECKLINK(a) CR (a, FAT_OFILE, CheckLink, FAT_OFILE_SIGNATURE) + +#define OFILE_FROM_CHILDLINK(a) CR (a, FAT_OFILE, ChildLink, FAT_OFILE_SIGNATURE) + +// +// Minimum sector size is 512B, Maximum sector size is 4096B +// Max sectors per cluster is 128 +// +#define MAX_BLOCK_ALIGNMENT 12 +#define MIN_BLOCK_ALIGNMENT 9 +#define MAX_SECTORS_PER_CLUSTER_ALIGNMENT 7 + +// +// Efi Time Definition +// +#define IS_LEAP_YEAR(a) (((a) % 4 == 0) && (((a) % 100 != 0) || ((a) % 400 == 0))) + +// +// Minimum fat page size is 8K, maximum fat page alignment is 32K +// Minimum data page size is 8K, maximum fat page alignment is 64K +// +#define FAT_FATCACHE_PAGE_MIN_ALIGNMENT 13 +#define FAT_FATCACHE_PAGE_MAX_ALIGNMENT 15 +#define FAT_DATACACHE_PAGE_MIN_ALIGNMENT 13 +#define FAT_DATACACHE_PAGE_MAX_ALIGNMENT 16 +#define FAT_DATACACHE_GROUP_COUNT 64 +#define FAT_FATCACHE_GROUP_MIN_COUNT 1 +#define FAT_FATCACHE_GROUP_MAX_COUNT 16 + +// +// Used in 8.3 generation algorithm +// +#define MAX_SPEC_RETRY 4 +#define SPEC_BASE_TAG_LEN 6 +#define HASH_BASE_TAG_LEN 2 +#define HASH_VALUE_TAG_LEN (SPEC_BASE_TAG_LEN - HASH_BASE_TAG_LEN) + +// +// Path name separator is back slash +// +#define PATH_NAME_SEPARATOR L'\\' + + +#define EFI_PATH_STRING_LENGTH 260 +#define EFI_FILE_STRING_LENGTH 255 +#define FAT_MAX_ALLOCATE_SIZE 0xA00000 +#define LC_ISO_639_2_ENTRY_SIZE 3 +#define MAX_LANG_CODE_SIZE 100 + +#define FAT_MAX_DIR_CACHE_COUNT 8 +#define FAT_MAX_DIRENTRY_COUNT 0xFFFF +typedef CHAR8 LC_ISO_639_2; + +// +// The fat types we support +// +typedef enum { + FAT12, + FAT16, + FAT32, + FatUndefined +} FAT_VOLUME_TYPE; + +typedef enum { + CACHE_FAT, + CACHE_DATA, + CACHE_MAX_TYPE +} CACHE_DATA_TYPE; + +// +// Used in FatDiskIo +// +typedef enum { + READ_DISK = 0, // raw disk read + WRITE_DISK = 1, // raw disk write + READ_FAT = 2, // read fat cache + WRITE_FAT = 3, // write fat cache + READ_DATA = 6, // read data cache + WRITE_DATA = 7 // write data cache +} IO_MODE; + +#define CACHE_ENABLED(a) ((a) >= 2) +#define RAW_ACCESS(a) ((IO_MODE)((a) & 0x1)) +#define CACHE_TYPE(a) ((CACHE_DATA_TYPE)((a) >> 2)) + +// +// Disk cache tag +// +typedef struct { + UINTN PageNo; + UINTN RealSize; + BOOLEAN Dirty; +} CACHE_TAG; + +typedef struct { + UINT64 BaseAddress; + UINT64 LimitAddress; + UINT8 *CacheBase; + BOOLEAN Dirty; + UINT8 PageAlignment; + UINTN GroupMask; + CACHE_TAG CacheTag[FAT_DATACACHE_GROUP_COUNT]; +} DISK_CACHE; + +// +// Hash table size +// +#define HASH_TABLE_SIZE 0x400 +#define HASH_TABLE_MASK (HASH_TABLE_SIZE - 1) + +// +// The directory entry for opened directory +// +typedef struct _FAT_DIRENT { + UINTN Signature; + UINT16 EntryPos; // The position of this directory entry in the parent directory file + UINT8 EntryCount; // The count of the directory entry in the parent directory file + BOOLEAN Invalid; // Indicate whether this directory entry is valid + CHAR16 *FileString; // The unicode long file name for this directory entry + struct _FAT_OFILE *OFile; // The OFile of the corresponding directory entry + struct _FAT_DIRENT *ShortNameForwardLink; // Hash successor link for short filename + struct _FAT_DIRENT *LongNameForwardLink; // Hash successor link for long filename + LIST_ENTRY Link; // Connection of every directory entry + FAT_DIRECTORY_ENTRY Entry; // The physical directory entry stored in disk +} FAT_DIRENT; + +typedef struct _FAT_ODIR { + UINTN Signature; + UINT32 CurrentEndPos; // Current end position of the directory + UINT32 CurrentPos; // Current position of the directory + LIST_ENTRY *CurrentCursor; // Current directory entry pointer + LIST_ENTRY ChildList; // List of all directory entries + BOOLEAN EndOfDir; // Indicate whether we have reached the end of the directory + LIST_ENTRY DirCacheLink; // Linked in Volume->DirCacheList when discarded + UINTN DirCacheTag; // The identification of the directory when in directory cache + FAT_DIRENT *LongNameHashTable[HASH_TABLE_SIZE]; + FAT_DIRENT *ShortNameHashTable[HASH_TABLE_SIZE]; +} FAT_ODIR; + +typedef struct { + UINTN Signature; + EFI_FILE_PROTOCOL Handle; + UINT64 Position; + BOOLEAN ReadOnly; + struct _FAT_OFILE *OFile; + LIST_ENTRY Tasks; // List of all FAT_TASKs + LIST_ENTRY Link; // Link to other IFiles +} FAT_IFILE; + +typedef struct { + UINTN Signature; + EFI_FILE_IO_TOKEN *FileIoToken; + FAT_IFILE *IFile; + LIST_ENTRY Subtasks; // List of all FAT_SUBTASKs + LIST_ENTRY Link; // Link to other FAT_TASKs +} FAT_TASK; + +typedef struct { + UINTN Signature; + EFI_DISK_IO2_TOKEN DiskIo2Token; + FAT_TASK *Task; + BOOLEAN Write; + UINT64 Offset; + VOID *Buffer; + UINTN BufferSize; + LIST_ENTRY Link; +} FAT_SUBTASK; + +// +// FAT_OFILE - Each opened file +// +typedef struct _FAT_OFILE { + UINTN Signature; + struct _FAT_VOLUME *Volume; + // + // A permanant error code to return to all accesses to + // this opened file + // + EFI_STATUS Error; + // + // A list of the IFILE instances for this OFile + // + LIST_ENTRY Opens; + + // + // The dynamic infomation + // + UINTN FileSize; + UINTN FileCluster; + UINTN FileCurrentCluster; + UINTN FileLastCluster; + + // + // Dirty is set if there have been any updates to the + // file + // Archive is set if the archive attribute in the file's + // directory entry needs to be set when performing flush + // PreserveLastMod is set if the last modification of the + // file is specified by SetInfo API + // + BOOLEAN Dirty; + BOOLEAN IsFixedRootDir; + BOOLEAN PreserveLastModification; + BOOLEAN Archive; + // + // Set by an OFile SetPosition + // + UINTN Position; // within file + UINT64 PosDisk; // on the disk + UINTN PosRem; // remaining in this disk run + // + // The opened parent, full path length and currently opened child files + // + struct _FAT_OFILE *Parent; + UINTN FullPathLen; + LIST_ENTRY ChildHead; + LIST_ENTRY ChildLink; + + // + // The opened directory structure for a directory; if this + // OFile represents a file, then ODir = NULL + // + FAT_ODIR *ODir; + // + // The directory entry for the Ofile + // + FAT_DIRENT *DirEnt; + + // + // Link in Volume's reference list + // + LIST_ENTRY CheckLink; +} FAT_OFILE; + +typedef struct _FAT_VOLUME { + UINTN Signature; + + EFI_HANDLE Handle; + BOOLEAN Valid; + BOOLEAN DiskError; + + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL VolumeInterface; + + // + // If opened, the parent handle and BlockIo interface + // + EFI_BLOCK_IO_PROTOCOL *BlockIo; + EFI_DISK_IO_PROTOCOL *DiskIo; + EFI_DISK_IO2_PROTOCOL *DiskIo2; + UINT32 MediaId; + BOOLEAN ReadOnly; + + // + // Computed values from fat bpb info + // + UINT64 VolumeSize; + UINT64 FatPos; // Disk pos of fat tables + UINT64 RootPos; // Disk pos of root directory + UINT64 FirstClusterPos; // Disk pos of first cluster + UINTN FatSize; // Number of bytes in each fat + UINTN MaxCluster; // Max cluster number + UINTN ClusterSize; // Cluster size of fat partition + UINT8 ClusterAlignment; // Equal to log_2 (clustersize); + FAT_VOLUME_TYPE FatType; + + // + // Current part of fat table that's present + // + UINT64 FatEntryPos; // Location of buffer + UINTN FatEntrySize; // Size of buffer + UINT32 FatEntryBuffer; // The buffer + FAT_INFO_SECTOR FatInfoSector; // Free cluster info + UINTN FreeInfoPos; // Pos with the free cluster info + BOOLEAN FreeInfoValid; // If free cluster info is valid + // + // Unpacked Fat BPB info + // + UINTN NumFats; + UINTN RootEntries; // < FAT32, root dir is fixed size + UINTN RootCluster; // >= FAT32, root cluster chain head + // + // info for marking the volume dirty or not + // + BOOLEAN FatDirty; // If fat-entries have been updated + UINT32 DirtyValue; + UINT32 NotDirtyValue; + + // + // The root directory entry and opened root file + // + FAT_DIRENT RootDirEnt; + // + // File Name of root OFile, it is empty string + // + CHAR16 RootFileString[1]; + struct _FAT_OFILE *Root; + + // + // New OFiles are added to this list so they + // can be cleaned up if they aren't referenced. + // + LIST_ENTRY CheckRef; + + // + // Directory cache List + // + LIST_ENTRY DirCacheList; + UINTN DirCacheCount; + + // + // Disk Cache for this volume + // + VOID *CacheBuffer; + DISK_CACHE DiskCache[CACHE_MAX_TYPE]; +} FAT_VOLUME; + +// +// Function Prototypes +// +EFI_STATUS +EFIAPI +FatOpen ( + IN EFI_FILE_PROTOCOL *FHand, + OUT EFI_FILE_PROTOCOL **NewHandle, + IN CHAR16 *FileName, + IN UINT64 OpenMode, + IN UINT64 Attributes + ) +/*++ +Routine Description: + + Implements Open() of Simple File System Protocol. + +Arguments: + + FHand - File handle of the file serves as a starting reference point. + NewHandle - Handle of the file that is newly opened. + FileName - File name relative to FHand. + OpenMode - Open mode. + Attributes - Attributes to set if the file is created. + +Returns: + + EFI_INVALID_PARAMETER - The FileName is NULL or the file string is empty. + The OpenMode is not supported. + The Attributes is not the valid attributes. + EFI_OUT_OF_RESOURCES - Can not allocate the memory for file string. + EFI_SUCCESS - Open the file successfully. + Others - The status of open file. + +--*/ +; + +EFI_STATUS +EFIAPI +FatOpenEx ( + IN EFI_FILE_PROTOCOL *FHand, + OUT EFI_FILE_PROTOCOL **NewHandle, + IN CHAR16 *FileName, + IN UINT64 OpenMode, + IN UINT64 Attributes, + IN OUT EFI_FILE_IO_TOKEN *Token + ) +/*++ +Routine Description: + + Implements OpenEx() of Simple File System Protocol. + +Arguments: + + FHand - File handle of the file serves as a starting reference point. + NewHandle - Handle of the file that is newly opened. + FileName - File name relative to FHand. + OpenMode - Open mode. + Attributes - Attributes to set if the file is created. + Token - A pointer to the token associated with the transaction. + +Returns: + + EFI_INVALID_PARAMETER - The FileName is NULL or the file string is empty. + The OpenMode is not supported. + The Attributes is not the valid attributes. + EFI_OUT_OF_RESOURCES - Can not allocate the memory for file string. + EFI_SUCCESS - Open the file successfully. + Others - The status of open file. + +--*/ +; + +EFI_STATUS +EFIAPI +FatGetPosition ( + IN EFI_FILE_PROTOCOL *FHand, + OUT UINT64 *Position + ) +/*++ + +Routine Description: + + Get the file's position of the file + +Arguments: + + FHand - The handle of file. + Position - The file's position of the file. + +Returns: + + EFI_SUCCESS - Get the info successfully. + EFI_DEVICE_ERROR - Can not find the OFile for the file. + EFI_UNSUPPORTED - The open file is not a file. + +--*/ +; + +EFI_STATUS +EFIAPI +FatGetInfo ( + IN EFI_FILE_PROTOCOL *FHand, + IN EFI_GUID *Type, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Get the some types info of the file into Buffer + +Arguments: + + FHand - The handle of file. + Type - The type of the info. + BufferSize - Size of Buffer. + Buffer - Buffer containing volume info. + +Returns: + + EFI_SUCCESS - Get the info successfully. + EFI_DEVICE_ERROR - Can not find the OFile for the file. + +--*/ +; + +EFI_STATUS +EFIAPI +FatSetInfo ( + IN EFI_FILE_PROTOCOL *FHand, + IN EFI_GUID *Type, + IN UINTN BufferSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Set the some types info of the file into Buffer + +Arguments: + + FHand - The handle of file. + Type - The type of the info. + BufferSize - Size of Buffer. + Buffer - Buffer containing volume info. + +Returns: + + EFI_SUCCESS - Set the info successfully. + EFI_DEVICE_ERROR - Can not find the OFile for the file. + +--*/ +; + +EFI_STATUS +EFIAPI +FatFlush ( + IN EFI_FILE_PROTOCOL *FHand + ) +/*++ + +Routine Description: + + Flushes all data associated with the file handle + +Arguments: + + FHand - Handle to file to flush + +Returns: + + EFI_SUCCESS - Flushed the file successfully + EFI_WRITE_PROTECTED - The volume is read only + EFI_ACCESS_DENIED - The volume is not read only + but the file is read only + Others - Flushing of the file is failed + +--*/ +; + +EFI_STATUS +EFIAPI +FatFlushEx ( + IN EFI_FILE_PROTOCOL *FHand, + IN EFI_FILE_IO_TOKEN *Token + ) +/*++ + +Routine Description: + + Flushes all data associated with the file handle. + +Arguments: + + FHand - Handle to file to flush. + Token - A pointer to the token associated with the transaction. + +Returns: + + EFI_SUCCESS - Flushed the file successfully. + EFI_WRITE_PROTECTED - The volume is read only. + EFI_ACCESS_DENIED - The file is read only. + Others - Flushing of the file failed. + +--*/ +; + +EFI_STATUS +EFIAPI +FatClose ( + IN EFI_FILE_PROTOCOL *FHand + ) +/*++ + +Routine Description: + + Flushes & Closes the file handle. + +Arguments: + + FHand - Handle to the file to delete. + +Returns: + + EFI_SUCCESS - Closed the file successfully. + +--*/ +; + +EFI_STATUS +EFIAPI +FatDelete ( + IN EFI_FILE_PROTOCOL *FHand + ) +/*++ + +Routine Description: + + Deletes the file & Closes the file handle. + +Arguments: + + FHand - Handle to the file to delete. + +Returns: + + EFI_SUCCESS - Delete the file successfully. + EFI_WARN_DELETE_FAILURE - Fail to delete the file. + +--*/ +; + +EFI_STATUS +EFIAPI +FatSetPosition ( + IN EFI_FILE_PROTOCOL *FHand, + IN UINT64 Position + ) +/*++ + +Routine Description: + + Set the file's position of the file + +Arguments: + + FHand - The handle of file + Position - The file's position of the file + +Returns: + + EFI_SUCCESS - Set the info successfully + EFI_DEVICE_ERROR - Can not find the OFile for the file + EFI_UNSUPPORTED - Set a directory with a not-zero position + +--*/ +; + +EFI_STATUS +EFIAPI +FatRead ( + IN EFI_FILE_PROTOCOL *FHand, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Get the file info. + +Arguments: + + FHand - The handle of the file. + BufferSize - Size of Buffer. + Buffer - Buffer containing read data. + +Returns: + + EFI_SUCCESS - Get the file info successfully. + EFI_DEVICE_ERROR - Can not find the OFile for the file. + EFI_VOLUME_CORRUPTED - The file type of open file is error. + other - An error occurred when operation the disk. + +--*/ +; + +EFI_STATUS +EFIAPI +FatReadEx ( + IN EFI_FILE_PROTOCOL *FHand, + IN OUT EFI_FILE_IO_TOKEN *Token + ) +/*++ + +Routine Description: + + Get the file info. + +Arguments: + + FHand - The handle of the file. + Token - A pointer to the token associated with the transaction. + +Returns: + + EFI_SUCCESS - Get the file info successfully. + EFI_DEVICE_ERROR - Can not find the OFile for the file. + EFI_VOLUME_CORRUPTED - The file type of open file is error. + other - An error occurred when operation the disk. + +--*/ +; + +EFI_STATUS +EFIAPI +FatWrite ( + IN EFI_FILE_PROTOCOL *FHand, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Set the file info. + +Arguments: + + FHand - The handle of the file. + BufferSize - Size of Buffer. + Buffer - Buffer containing write data. + +Returns: + + EFI_SUCCESS - Set the file info successfully. + EFI_WRITE_PROTECTED - The disk is write protected. + EFI_ACCESS_DENIED - The file is read-only. + EFI_DEVICE_ERROR - The OFile is not valid. + EFI_UNSUPPORTED - The open file is not a file. + - The writing file size is larger than 4GB. + other - An error occurred when operation the disk. + +--*/ +; + +EFI_STATUS +EFIAPI +FatWriteEx ( + IN EFI_FILE_PROTOCOL *FHand, + IN OUT EFI_FILE_IO_TOKEN *Token + ) +/*++ + +Routine Description: + + Get the file info. + +Arguments: + + FHand - The handle of the file. + Token - A pointer to the token associated with the transaction. + +Returns: + + EFI_SUCCESS - Get the file info successfully. + EFI_DEVICE_ERROR - Can not find the OFile for the file. + EFI_VOLUME_CORRUPTED - The file type of open file is error. + other - An error occurred when operation the disk. + +--*/ +; + +// +// DiskCache.c +// +EFI_STATUS +FatInitializeDiskCache ( + IN FAT_VOLUME *Volume + ); + +EFI_STATUS +FatAccessCache ( + IN FAT_VOLUME *Volume, + IN CACHE_DATA_TYPE CacheDataType, + IN IO_MODE IoMode, + IN UINT64 Offset, + IN UINTN BufferSize, + IN OUT UINT8 *Buffer, + IN FAT_TASK *Task + ); + +EFI_STATUS +FatVolumeFlushCache ( + IN FAT_VOLUME *Volume, + IN FAT_TASK *Task + ); + +// +// Flush.c +// +EFI_STATUS +FatOFileFlush ( + IN FAT_OFILE *OFile + ); + +BOOLEAN +FatCheckOFileRef ( + IN FAT_OFILE *OFile + ); + +VOID +FatSetVolumeError ( + IN FAT_OFILE *OFile, + IN EFI_STATUS Status + ); + +EFI_STATUS +FatIFileClose ( + FAT_IFILE *IFile + ); + +EFI_STATUS +FatCleanupVolume ( + IN FAT_VOLUME *Volume, + IN FAT_OFILE *OFile, + IN EFI_STATUS EfiStatus, + IN FAT_TASK *Task + ); + +// +// FileSpace.c +// +EFI_STATUS +FatShrinkEof ( + IN FAT_OFILE *OFile + ); + +EFI_STATUS +FatGrowEof ( + IN FAT_OFILE *OFile, + IN UINT64 NewSizeInBytes + ); + +UINTN +FatPhysicalDirSize ( + IN FAT_VOLUME *Volume, + IN UINTN Cluster + ); + +UINT64 +FatPhysicalFileSize ( + IN FAT_VOLUME *Volume, + IN UINTN RealSize + ); + +EFI_STATUS +FatOFilePosition ( + IN FAT_OFILE *OFile, + IN UINTN Position, + IN UINTN PosLimit + ); + +VOID +FatComputeFreeInfo ( + IN FAT_VOLUME *Volume + ); + +// +// Init.c +// +EFI_STATUS +FatAllocateVolume ( + IN EFI_HANDLE Handle, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN EFI_DISK_IO2_PROTOCOL *DiskIo2, + IN EFI_BLOCK_IO_PROTOCOL *BlockIo + ); + +EFI_STATUS +FatOpenDevice ( + IN OUT FAT_VOLUME *Volume + ); + +EFI_STATUS +FatAbandonVolume ( + IN FAT_VOLUME *Volume + ); + +// +// Misc.c +// +FAT_TASK * +FatCreateTask ( + FAT_IFILE *IFile, + EFI_FILE_IO_TOKEN *Token + ); + +VOID +FatDestroyTask ( + FAT_TASK *Task + ); + +VOID +FatWaitNonblockingTask ( + FAT_IFILE *IFile + ); + +LIST_ENTRY * +FatDestroySubtask ( + FAT_SUBTASK *Subtask + ); + +EFI_STATUS +FatQueueTask ( + IN FAT_IFILE *IFile, + IN FAT_TASK *Task + ); + +EFI_STATUS +FatAccessVolumeDirty ( + IN FAT_VOLUME *Volume, + IN IO_MODE IoMode, + IN VOID *DirtyValue + ); + +EFI_STATUS +FatDiskIo ( + IN FAT_VOLUME *Volume, + IN IO_MODE IoMode, + IN UINT64 Offset, + IN UINTN BufferSize, + IN OUT VOID *Buffer, + IN FAT_TASK *Task + ); + +VOID +FatAcquireLock ( + VOID + ); + +VOID +FatReleaseLock ( + VOID + ); + +EFI_STATUS +FatAcquireLockOrFail ( + VOID + ); + +VOID +FatFreeDirEnt ( + IN FAT_DIRENT *DirEnt + ); + +VOID +FatFreeVolume ( + IN FAT_VOLUME *Volume + ); + +VOID +FatEfiTimeToFatTime ( + IN EFI_TIME *ETime, + OUT FAT_DATE_TIME *FTime + ); + +VOID +FatFatTimeToEfiTime ( + IN FAT_DATE_TIME *FTime, + OUT EFI_TIME *ETime + ); + +VOID +FatGetCurrentFatTime ( + OUT FAT_DATE_TIME *FatTime + ); + +BOOLEAN +FatIsValidTime ( + IN EFI_TIME *Time + ); + +// +// UnicodeCollation.c +// +EFI_STATUS +InitializeUnicodeCollationSupport ( + IN EFI_HANDLE AgentHandle + ); + +VOID +FatFatToStr ( + IN UINTN FatSize, + IN CHAR8 *Fat, + OUT CHAR16 *String + ); + +BOOLEAN +FatStrToFat ( + IN CHAR16 *String, + IN UINTN FatSize, + OUT CHAR8 *Fat + ); + +VOID +FatStrLwr ( + IN CHAR16 *Str + ); + +VOID +FatStrUpr ( + IN CHAR16 *Str + ); + +INTN +FatStriCmp ( + IN CHAR16 *Str1, + IN CHAR16 *Str2 + ); + +// +// Open.c +// +EFI_STATUS +FatOFileOpen ( + IN FAT_OFILE *OFile, + OUT FAT_IFILE **NewIFile, + IN CHAR16 *FileName, + IN UINT64 OpenMode, + IN UINT8 Attributes + ); + +EFI_STATUS +FatAllocateIFile ( + IN FAT_OFILE *OFile, + OUT FAT_IFILE **PtrIFile + ); + +// +// OpenVolume.c +// +EFI_STATUS +EFIAPI +FatOpenVolume ( + IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This, + OUT EFI_FILE_PROTOCOL **File + ); + +// +// ReadWrite.c +// +EFI_STATUS +FatAccessOFile ( + IN FAT_OFILE *OFile, + IN IO_MODE IoMode, + IN UINTN Position, + IN UINTN *DataBufferSize, + IN UINT8 *UserBuffer, + IN FAT_TASK *Task + ); + +EFI_STATUS +FatExpandOFile ( + IN FAT_OFILE *OFile, + IN UINT64 ExpandedSize + ); + +EFI_STATUS +FatWriteZeroPool ( + IN FAT_OFILE *OFile, + IN UINTN WritePos + ); + +EFI_STATUS +FatTruncateOFile ( + IN FAT_OFILE *OFile, + IN UINTN TruncatedSize + ); + +// +// DirectoryManage.c +// +VOID +FatResetODirCursor ( + IN FAT_OFILE *OFile + ); + +EFI_STATUS +FatGetNextDirEnt ( + IN FAT_OFILE *OFILE, + OUT FAT_DIRENT **PtrDirEnt + ); + +EFI_STATUS +FatRemoveDirEnt ( + IN FAT_OFILE *OFile, + IN FAT_DIRENT *DirEnt + ); + +EFI_STATUS +FatStoreDirEnt ( + IN FAT_OFILE *OFile, + IN FAT_DIRENT *DirEnt + ); + +EFI_STATUS +FatCreateDirEnt ( + IN FAT_OFILE *OFile, + IN CHAR16 *FileName, + IN UINT8 Attributes, + OUT FAT_DIRENT **PtrDirEnt + ); + +BOOLEAN +FatIsDotDirEnt ( + IN FAT_DIRENT *DirEnt + ); + +VOID +FatUpdateDirEntClusterSizeInfo ( + IN FAT_OFILE *OFile + ); + +VOID +FatCloneDirEnt ( + IN FAT_DIRENT *DirEnt1, + IN FAT_DIRENT *DirEnt2 + ); + +EFI_STATUS +FatGetDirEntInfo ( + IN FAT_VOLUME *Volume, + IN FAT_DIRENT *DirEnt, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ); + +EFI_STATUS +FatOpenDirEnt ( + IN FAT_OFILE *OFile, + IN FAT_DIRENT *DirEnt + ); + +EFI_STATUS +FatCreateDotDirEnts ( + IN FAT_OFILE *OFile + ); + +VOID +FatCloseDirEnt ( + IN FAT_DIRENT *DirEnt + ); + +EFI_STATUS +FatLocateOFile ( + IN OUT FAT_OFILE **PtrOFile, + IN CHAR16 *FileName, + IN UINT8 Attributes, + OUT CHAR16 *NewFileName + ); + +EFI_STATUS +FatGetVolumeEntry ( + IN FAT_VOLUME *Volume, + IN CHAR16 *Name + ); + +EFI_STATUS +FatSetVolumeEntry ( + IN FAT_VOLUME *Volume, + IN CHAR16 *Name + ); + +// +// Hash.c +// +FAT_DIRENT ** +FatLongNameHashSearch ( + IN FAT_ODIR *ODir, + IN CHAR16 *LongNameString + ); + +FAT_DIRENT ** +FatShortNameHashSearch ( + IN FAT_ODIR *ODir, + IN CHAR8 *ShortNameString + ); + +VOID +FatInsertToHashTable ( + IN FAT_ODIR *ODir, + IN FAT_DIRENT *DirEnt + ); + +VOID +FatDeleteFromHashTable ( + IN FAT_ODIR *ODir, + IN FAT_DIRENT *DirEnt + ); + +// +// FileName.c +// +BOOLEAN +FatCheckIs8Dot3Name ( + IN CHAR16 *FileName, + OUT CHAR8 *File8Dot3Name + ); + +VOID +FatCreate8Dot3Name ( + IN FAT_OFILE *Parent, + IN FAT_DIRENT *DirEnt + ); + +VOID +FatNameToStr ( + IN CHAR8 *FatName, + IN UINTN Len, + IN UINTN LowerCase, + IN CHAR16 *Str + ); + +VOID +FatSetCaseFlag ( + IN FAT_DIRENT *DirEnt + ); + +VOID +FatGetFileNameViaCaseFlag ( + IN FAT_DIRENT *DirEnt, + OUT CHAR16 *FileString + ); + +UINT8 +FatCheckSum ( + IN CHAR8 *ShortNameString + ); + +CHAR16* +FatGetNextNameComponent ( + IN CHAR16 *Path, + OUT CHAR16 *Name + ); + +BOOLEAN +FatFileNameIsValid ( + IN CHAR16 *InputFileName, + OUT CHAR16 *OutputFileName + ); + +// +// DirectoryCache.c +// +VOID +FatDiscardODir ( + IN FAT_OFILE *OFile + ); + +VOID +FatRequestODir ( + IN FAT_OFILE *OFile + ); + +VOID +FatCleanupODirCache ( + IN FAT_VOLUME *Volume + ); + +// +// Global Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gFatDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gFatComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gFatComponentName2; +extern EFI_LOCK FatFsLock; +extern EFI_LOCK FatTaskLock; +extern EFI_FILE_PROTOCOL FatFileInterface; + +#endif diff --git a/FatPkg/EnhancedFatDxe/Fat.inf b/FatPkg/EnhancedFatDxe/Fat.inf new file mode 100644 index 0000000..19abf63 --- /dev/null +++ b/FatPkg/EnhancedFatDxe/Fat.inf @@ -0,0 +1,121 @@ +## @file +# Component description file for FAT module. +# +# This UEFI driver detects the FAT file system in the disk. +# It also produces the Simple File System protocol for the consumer to +# perform file and directory operations on the disk. +# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.
+# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# Neither the name of Intel nor the names of its contributors may +# be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Additional terms: In addition to the forgoing, redistribution and use +# of the code is conditioned upon the FAT 32 File System Driver and all +# derivative works thereof being used for and designed only to read +# and/or write to a file system that is directly managed by an +# Extensible Firmware Interface (EFI) implementation or by an emulator +# of an EFI implementation. +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Fat + MODULE_UNI_FILE = Fat.uni + FILE_GUID = 961578FE-B6B7-44c3-AF35-6BC705CD2B1F + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = FatEntryPoint + UNLOAD_IMAGE = FatUnload + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# +# DRIVER_BINDING = gFatDriverBinding +# COMPONENT_NAME = gFatComponentName +# COMPONENT_NAME2 = gFatComponentName2 +# + +[Sources] + DirectoryCache.c + DiskCache.c + FileName.c + Hash.c + DirectoryManage.c + ComponentName.c + FatFileSystem.h + Fat.h + ReadWrite.c + OpenVolume.c + Open.c + Misc.c + Init.c + Info.c + FileSpace.c + Flush.c + Fat.c + Delete.c + Data.c + UnicodeCollation.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + MemoryAllocationLib + BaseMemoryLib + BaseLib + UefiLib + UefiDriverEntryPoint + DebugLib + PcdLib + +[Guids] + gEfiFileInfoGuid ## SOMETIMES_CONSUMES ## UNDEFINED + gEfiFileSystemInfoGuid ## SOMETIMES_CONSUMES ## UNDEFINED + gEfiFileSystemVolumeLabelInfoIdGuid ## SOMETIMES_CONSUMES ## UNDEFINED + +[Protocols] + gEfiDiskIoProtocolGuid ## TO_START + gEfiDiskIo2ProtocolGuid ## TO_START + gEfiBlockIoProtocolGuid ## TO_START + gEfiSimpleFileSystemProtocolGuid ## BY_START + gEfiUnicodeCollationProtocolGuid ## TO_START + gEfiUnicodeCollation2ProtocolGuid ## TO_START + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLang ## SOMETIMES_CONSUMES + gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultPlatformLang ## SOMETIMES_CONSUMES +[UserExtensions.TianoCore."ExtraFiles"] + FatExtra.uni diff --git a/FatPkg/EnhancedFatDxe/Fat.uni b/FatPkg/EnhancedFatDxe/Fat.uni new file mode 100644 index 0000000000000000000000000000000000000000..1b5fe93b442eb62faf2f6b815e66fea192aec336 GIT binary patch literal 5114 zcmd6rZ*Ln#5XSd465rvJzA30}pdcX?gt*vFW65!XeQD^cDzTGbHFl!dZpfDhp5Kng zb4Q#|0Rm*%cel4Y^UO1UcGkcBx}CODq3`GV6zPX_o+jxsouyCHCmQ8lD_x~&y4LSZ zq0f=TTdQ4Po1f z){QlS9XFZ<8!&yRu`3}%+KI-@BVb3C5zWdZzoX0d_ze^<^rqB%W`u08VZl6O#>-=Q<-4?#2I>1X7lCe&XAmQc zEag<}xt(~=cv)t7?sfdR)NK41b53R7Oe>5vXL+8jxz#(o1aCy0KO<+cM&-H+cJtl+4Bza(zO-7tdKI-jf$Rpi$5OpU z5rH6eJAH2C01|n!DqY9IO5R}QT`kK_vo5PWmecGb@CJ*lF)Zk{IAK4eCipXZqwj2F zobP-{JJ%C?a6Mbd({o9<6%sNs7<6u}Vv*6*p^8&m7WRp#S#zzl zO0${!D($KE54C2P4zw3m=~z{Mpxv82f$>8<9i%sUYHPHuk)8BbzpP|dOK%S~GSH0I z8mlz6r?Fn1Kgcr5)XyuK+t&={?x;to^vsN~drR8Uita64eI-}4cG6E7QAh8Y$9iV( zYqY1UAv7BXd3BXXhpSz#FT6czZfmqJyi_kkQt0_Whyn}p_Vuk+QbEgnxBO$Yf^b)B z_9bH=-FqucrL=Z4;wszacG5FdLgM!AW(xyTDOrb-G0?28p{W5}`!|6wa$G4?H5h8o|IK73s1o(L?2;Xt2u#$m|8Jjl7((%mq9 zt64qG@!TNtj`Y-Nu!Bu-1}`SZ&{*u56dNZqhS_3|N2~|UK%XPA3_^06?vkuO);nT} zXlO}?X{TyuMa-4Dx5$A%DhuAno7W=I4leb)YUcx?t;6tuLr! zwoZPj-LrYx^0VnzIzK&pUTo(**w49sl7WZIT4jo^z&bJOwQuu2{$4ye4_IvY=}L?V zx6rx?+xcA&a@pxG#F^QF4VU>uY5XD)?jxRTt@nT4L!4y{c;rOiII}j-&pLLzfF&^cbt9+{hQMMh4y}%zE0ny zH|e#W_vc!sbDd4PmF6Z8O~S^OR$9V@1W2q6ERC$+>D#2=0_|4%KJBDo`eET)!7~hr ziRA6iX}Z^wEflZrLthpCR(igXR3p?EvX(tRjnxy)KWg?e&|XOvZyvNZlebmOmN9x} z3shCQ()zh%i3N;jB8J^h(k*D6jk73fU* zT%~N0iV2#Bu;j|bSuWM;PCIku&e6&LRT`x|)%;pJ>NL>JGfKy*?!(m8jOPzE8l-m` zbu`=2{7(9yUv?tZ*6N{VhLZS6b0f{|X|5OY!_eJI{n&|YUlPdfq$52I^jt4RU_;hH zgY6Cd=bijxwVU3{8u;pvV?WXdn(gV|2<^i#c8_AVp5JbL;qA$CN3(t5rEVEXrSU+B z3ODFG(04S~3R>i|=l{fNr9Hdab08f<+1{IDYRT$;ARdKZ+0Wgu*I)Rz8w?dpE$KRx zj-gQOOW%=nFk<#d|A&&VwHxLfMLey;>z1Ct(NP73v%Y@u8CKuvOJv9cF!uB*o<5Ip zK{QatfENso#!FF#X^_Dy{`X>J4;^VD3|^48g$B04xo)nl6*3ak;C;OmxmrA+0XwWX zZ@Tj=fte36yNnmseinz;=$)WxX;({`LdI2TGw}TP9P+6me)vjM%)Yaw*8Gm_5#y1b z$-qh&2KsaYhmnJM7-zGsr#gKnsh(u=*&y?dH0rLfgHLbla-NiP0^(!Y>B=s@ zKKtk^IoDcb4*XGR$fS~WtJ>_R>(KJqUl(UiOIJ|<7x_RfAuiTI?J%Zet;0E-kZX)w zZStwh)r>l2e~EGSJJ%O;S2!{&tfKLG#de!$)rPPTarT^o>UO z-2@({OLeJq1n$AyV?V?l{;RZQt9WeubR=dXdq`hmmWmzpa?6i}+XEn7S6b1wl9c9{gPg z_EYV|It-IFxg&DsIF~M^(LMR5@|k+Y8JkG@Hg>P;aNQpj`}A|X0r5rwH_Z|va}G*w z4D^3m`?|Bhd;NCk#M4)iBl(S;tf3}-)XAf(;+FDFPJR8Tdw}}Ro!-@`ugv3Ss6yMT jK+KuApY!U@^sA_`me~+yXY0#(`aU!+=j+A-Er|aH#r2RJ literal 0 HcmV?d00001 diff --git a/FatPkg/EnhancedFatDxe/FatFileSystem.h b/FatPkg/EnhancedFatDxe/FatFileSystem.h new file mode 100644 index 0000000..4dd2295 --- /dev/null +++ b/FatPkg/EnhancedFatDxe/FatFileSystem.h @@ -0,0 +1,217 @@ +/*++ + +Copyright (c) 2005, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the Software +License Agreement which accompanies this distribution. + + +Module Name: + + FatFileSystem.h + +Abstract: + + Definitions for on-disk FAT structures + +Revision History + +--*/ + +#ifndef _FATFILESYSTEM_H_ +#define _FATFILESYSTEM_H_ + +#pragma pack(1) +// +// FAT info signature +// +#define FAT_INFO_SIGNATURE 0x41615252 +#define FAT_INFO_BEGIN_SIGNATURE 0x61417272 +#define FAT_INFO_END_SIGNATURE 0xAA550000 +// +// FAT entry values +// +#define FAT_CLUSTER_SPECIAL_EXT (-1 & (~0xF)) +#define FAT_CLUSTER_SPECIAL ((FAT_CLUSTER_SPECIAL_EXT) | 0x07) +#define FAT_CLUSTER_FREE 0 +#define FAT_CLUSTER_RESERVED (FAT_CLUSTER_SPECIAL) +#define FAT_CLUSTER_BAD (FAT_CLUSTER_SPECIAL) +#define FAT_CLUSTER_LAST (-1) +#define FAT_END_OF_FAT_CHAIN(Cluster) ((Cluster) > (FAT_CLUSTER_SPECIAL)) +#define FAT_MIN_CLUSTER 2 +#define FAT_MAX_FAT12_CLUSTER 0xFF5 +#define FAT_MAX_FAT16_CLUSTER 0xFFF5 +#define FAT_CLUSTER_SPECIAL_FAT12 0xFF7 +#define FAT_CLUSTER_SPECIAL_FAT16 0xFFF7 +#define FAT_CLUSTER_SPECIAL_FAT32 0x0FFFFFF7 +#define FAT_CLUSTER_MASK_FAT12 0xFFF +#define FAT_CLUSTER_UNMASK_FAT12 0xF000 +#define FAT_CLUSTER_MASK_FAT32 0x0FFFFFFF +#define FAT_CLUSTER_UNMASK_FAT32 0xF0000000 +#define FAT_POS_FAT12(a) ((a) * 3 / 2) +#define FAT_POS_FAT16(a) ((a) * 2) +#define FAT_POS_FAT32(a) ((a) * 4) +#define FAT_ODD_CLUSTER_FAT12(a) (((a) & 1) != 0) + + +// +// FAT attribute define +// +#define FAT_ATTRIBUTE_READ_ONLY 0x01 +#define FAT_ATTRIBUTE_HIDDEN 0x02 +#define FAT_ATTRIBUTE_SYSTEM 0x04 +#define FAT_ATTRIBUTE_VOLUME_ID 0x08 +#define FAT_ATTRIBUTE_DIRECTORY 0x10 +#define FAT_ATTRIBUTE_ARCHIVE 0x20 +#define FAT_ATTRIBUTE_DEVICE 0x40 +#define FAT_ATTRIBUTE_LFN 0x0F +// +// Some Long File Name definitions +// +#define FAT_LFN_LAST 0x40 // Ordinal field +#define MAX_LFN_ENTRIES 20 +#define LFN_CHAR1_LEN 5 +#define LFN_CHAR2_LEN 6 +#define LFN_CHAR3_LEN 2 +#define LFN_CHAR_TOTAL (LFN_CHAR1_LEN + LFN_CHAR2_LEN + LFN_CHAR3_LEN) +#define LFN_ENTRY_NUMBER(a) (((a) + LFN_CHAR_TOTAL - 1) / LFN_CHAR_TOTAL) +// +// Some 8.3 File Name definitions +// +#define FAT_MAIN_NAME_LEN 8 +#define FAT_EXTEND_NAME_LEN 3 +#define FAT_NAME_LEN (FAT_MAIN_NAME_LEN + FAT_EXTEND_NAME_LEN) +// +// Some directory entry information +// +#define FAT_ENTRY_INFO_OFFSET 13 +#define DELETE_ENTRY_MARK 0xE5 +#define EMPTY_ENTRY_MARK 0x00 + +// +// Volume dirty Mask +// +#define FAT16_DIRTY_MASK 0x7fff +#define FAT32_DIRTY_MASK 0xf7ffffff +// +// internal flag +// +#define FAT_CASE_MIXED 0x01 +#define FAT_CASE_NAME_LOWER 0x08 +#define FAT_CASE_EXT_LOWER 0x10 + +typedef struct { + UINT8 Ia32Jump[3]; + CHAR8 OemId[8]; + UINT16 SectorSize; + UINT8 SectorsPerCluster; + UINT16 ReservedSectors; + UINT8 NumFats; + UINT16 RootEntries; // < FAT32, root dir is fixed size + UINT16 Sectors; + UINT8 Media; + UINT16 SectorsPerFat; // < FAT32 + UINT16 SectorsPerTrack; // (ignored) + UINT16 Heads; // (ignored) + UINT32 HiddenSectors; // (ignored) + UINT32 LargeSectors; // Used if Sectors==0 +} FAT_BOOT_SECTOR_BASIC; + +typedef struct { + UINT8 PhysicalDriveNumber; // (ignored) + UINT8 CurrentHead; // holds boot_sector_dirty bit + UINT8 Signature; // (ignored) + CHAR8 Id[4]; + CHAR8 FatLabel[11]; + CHAR8 SystemId[8]; +} FAT_BOOT_SECTOR_EXT; + +typedef struct { + UINT32 LargeSectorsPerFat; // FAT32 + UINT16 ExtendedFlags; // FAT32 (ignored) + UINT16 FsVersion; // FAT32 (ignored) + UINT32 RootDirFirstCluster; // FAT32 + UINT16 FsInfoSector; // FAT32 + UINT16 BackupBootSector; // FAT32 + UINT8 Reserved[12]; // FAT32 (ignored) + UINT8 PhysicalDriveNumber; // (ignored) + UINT8 CurrentHead; // holds boot_sector_dirty bit + UINT8 Signature; // (ignored) + CHAR8 Id[4]; + CHAR8 FatLabel[11]; + CHAR8 SystemId[8]; +} FAT32_BOOT_SECTOR_EXT; + +typedef struct { + FAT_BOOT_SECTOR_BASIC FatBsb; + union { + FAT_BOOT_SECTOR_EXT FatBse; + FAT32_BOOT_SECTOR_EXT Fat32Bse; + } FatBse; +} FAT_BOOT_SECTOR; + +// +// FAT Info Structure +// +typedef struct { + UINT32 ClusterCount; + UINT32 NextCluster; +} FAT_FREE_INFO; + +typedef struct { + UINT32 Signature; + UINT8 ExtraBootCode[480]; + UINT32 InfoBeginSignature; + FAT_FREE_INFO FreeInfo; + UINT8 Reserved[12]; + UINT32 InfoEndSignature; +} FAT_INFO_SECTOR; + +// +// Directory Entry +// +#define FAT_MAX_YEAR_FROM_1980 0x7f +typedef struct { + UINT16 Day : 5; + UINT16 Month : 4; + UINT16 Year : 7; // From 1980 +} FAT_DATE; + +typedef struct { + UINT16 DoubleSecond : 5; + UINT16 Minute : 6; + UINT16 Hour : 5; +} FAT_TIME; + +typedef struct { + FAT_TIME Time; + FAT_DATE Date; +} FAT_DATE_TIME; + +typedef struct { + CHAR8 FileName[11]; // 8.3 filename + UINT8 Attributes; + UINT8 CaseFlag; + UINT8 CreateMillisecond; // (creation milliseconds - ignored) + FAT_DATE_TIME FileCreateTime; + FAT_DATE FileLastAccess; + UINT16 FileClusterHigh; // >= FAT32 + FAT_DATE_TIME FileModificationTime; + UINT16 FileCluster; + UINT32 FileSize; +} FAT_DIRECTORY_ENTRY; + +typedef struct { + UINT8 Ordinal; + CHAR8 Name1[10]; // (Really 5 chars, but not WCHAR aligned) + UINT8 Attributes; + UINT8 Type; + UINT8 Checksum; + CHAR16 Name2[6]; + UINT16 MustBeZero; + CHAR16 Name3[2]; +} FAT_DIRECTORY_LFN; + +#pragma pack() + +#endif diff --git a/FatPkg/EnhancedFatDxe/FileName.c b/FatPkg/EnhancedFatDxe/FileName.c new file mode 100644 index 0000000..1ba2706 --- /dev/null +++ b/FatPkg/EnhancedFatDxe/FileName.c @@ -0,0 +1,579 @@ +/*++ + +Copyright (c) 2005 - 2007, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the Software +License Agreement which accompanies this distribution. + + +Module Name: + + FileName.c + +Abstract: + + Functions for manipulating file names + +Revision History + +--*/ + +#include "Fat.h" + +BOOLEAN +FatCheckIs8Dot3Name ( + IN CHAR16 *FileName, + OUT CHAR8 *File8Dot3Name + ) +/*++ + +Routine Description: + + This function checks whether the input FileName is a valid 8.3 short name. + If the input FileName is a valid 8.3, the output is the 8.3 short name; + otherwise, the output is the base tag of 8.3 short name. + +Arguments: + + FileName - The input unicode filename. + File8Dot3Name - The output ascii 8.3 short name or base tag of 8.3 short name. + +Returns: + + TRUE - The input unicode filename is a valid 8.3 short name. + FALSE - The input unicode filename is not a valid 8.3 short name. + +--*/ +{ + BOOLEAN PossibleShortName; + CHAR16 *TempName; + CHAR16 *ExtendName; + CHAR16 *SeparateDot; + UINTN MainNameLen; + UINTN ExtendNameLen; + + PossibleShortName = TRUE; + SeparateDot = NULL; + SetMem (File8Dot3Name, FAT_NAME_LEN, ' '); + for (TempName = FileName; *TempName; TempName++) { + if (*TempName == L'.') { + SeparateDot = TempName; + } + } + + if (SeparateDot == NULL) { + // + // Extended filename is not detected + // + MainNameLen = TempName - FileName; + ExtendName = TempName; + ExtendNameLen = 0; + } else { + // + // Extended filename is detected + // + MainNameLen = SeparateDot - FileName; + ExtendName = SeparateDot + 1; + ExtendNameLen = TempName - ExtendName; + } + // + // We scan the filename for the second time + // to check if there exists any extra blanks and dots + // + while (--TempName >= FileName) { + if ((*TempName == L'.' || *TempName == L' ') && (TempName != SeparateDot)) { + // + // There exist extra blanks and dots + // + PossibleShortName = FALSE; + } + } + + if (MainNameLen == 0) { + PossibleShortName = FALSE; + } + + if (MainNameLen > FAT_MAIN_NAME_LEN) { + PossibleShortName = FALSE; + MainNameLen = FAT_MAIN_NAME_LEN; + } + + if (ExtendNameLen > FAT_EXTEND_NAME_LEN) { + PossibleShortName = FALSE; + ExtendNameLen = FAT_EXTEND_NAME_LEN; + } + + if (FatStrToFat (FileName, MainNameLen, File8Dot3Name)) { + PossibleShortName = FALSE; + } + + if (FatStrToFat (ExtendName, ExtendNameLen, File8Dot3Name + FAT_MAIN_NAME_LEN)) { + PossibleShortName = FALSE; + } + + return PossibleShortName; +} + +STATIC +UINTN +FatTrimAsciiTrailingBlanks ( + IN CHAR8 *Name, + IN UINTN Len + ) +/*++ + +Routine Description: + + Trim the trailing blanks of fat name. + +Arguments: + + Name - The Char8 string needs to be trimed. + Len - The length of the fat name. + +Returns: + + The real length of the fat name after the trailing blanks are trimmed. + +--*/ +{ + while (Len > 0 && Name[Len - 1] == ' ') { + Len--; + } + + return Len; +} + +VOID +FatNameToStr ( + IN CHAR8 *FatName, + IN UINTN Len, + IN UINTN LowerCase, + OUT CHAR16 *Str + ) +/*++ + +Routine Description: + + Convert the ascii fat name to the unicode string and strip trailing spaces, + and if necessary, convert the unicode string to lower case. + +Arguments: + + FatName - The Char8 string needs to be converted. + Len - The length of the fat name. + LowerCase - Indicate whether to convert the string to lower case. + Str - The result of the convertion. + +Returns: + + None. + +--*/ +{ + // + // First, trim the trailing blanks + // + Len = FatTrimAsciiTrailingBlanks (FatName, Len); + // + // Convert fat string to unicode string + // + FatFatToStr (Len, FatName, Str); + + // + // If the name is to be lower cased, do it now + // + if (LowerCase != 0) { + FatStrLwr (Str); + } +} + +VOID +FatCreate8Dot3Name ( + IN FAT_OFILE *Parent, + IN FAT_DIRENT *DirEnt + ) +/*++ + +Routine Description: + + This function generates 8Dot3 name from user specified name for a newly created file. + +Arguments: + + Parent - The parent directory. + DirEnt - The directory entry whose 8Dot3Name needs to be generated. + +Returns: + + None. + +--*/ +{ + CHAR8 *ShortName; + CHAR8 *ShortNameChar; + UINTN BaseTagLen; + UINTN Index; + UINTN Retry; + UINT8 Segment; + union { + UINT32 Crc; + struct HEX_DATA { + UINT8 Segment : HASH_VALUE_TAG_LEN; + } Hex[HASH_VALUE_TAG_LEN]; + } HashValue; + // + // Make sure the whole directory has been loaded + // + ASSERT (Parent->ODir->EndOfDir); + ShortName = DirEnt->Entry.FileName; + + // + // Trim trailing blanks of 8.3 name + // + BaseTagLen = FatTrimAsciiTrailingBlanks (ShortName, FAT_MAIN_NAME_LEN); + if (BaseTagLen > SPEC_BASE_TAG_LEN) { + BaseTagLen = SPEC_BASE_TAG_LEN; + } + // + // We first use the algorithm described by spec. + // + ShortNameChar = ShortName + BaseTagLen; + *ShortNameChar++ = '~'; + *ShortNameChar = '1'; + Retry = 0; + while (*FatShortNameHashSearch (Parent->ODir, ShortName) != NULL) { + *ShortNameChar = (CHAR8)(*ShortNameChar + 1); + if (++Retry == MAX_SPEC_RETRY) { + // + // We use new algorithm to generate 8.3 name + // + ASSERT (DirEnt->FileString != NULL); + gBS->CalculateCrc32 (DirEnt->FileString, StrSize (DirEnt->FileString), &HashValue.Crc); + + if (BaseTagLen > HASH_BASE_TAG_LEN) { + BaseTagLen = HASH_BASE_TAG_LEN; + } + + ShortNameChar = ShortName + BaseTagLen; + for (Index = 0; Index < HASH_VALUE_TAG_LEN; Index++) { + Segment = HashValue.Hex[Index].Segment; + if (Segment > 9) { + *ShortNameChar++ = (CHAR8)(Segment - 10 + 'A'); + } else { + *ShortNameChar++ = (CHAR8)(Segment + '0'); + } + } + + *ShortNameChar++ = '~'; + *ShortNameChar = '1'; + } + } +} + +STATIC +UINT8 +FatCheckNameCase ( + IN CHAR16 *Str, + IN UINT8 InCaseFlag + ) +/*++ + +Routine Description: + + Check the string is lower case or upper case + and it is used by fatname to dir entry count + +Arguments: + + Str - The string which needs to be checked. + InCaseFlag - The input case flag which is returned when the string is lower case. + +Returns: + + OutCaseFlag - The output case flag. + +--*/ +{ + CHAR16 Buffer[FAT_MAIN_NAME_LEN + 1 + FAT_EXTEND_NAME_LEN + 1]; + UINT8 OutCaseFlag; + + ASSERT (StrSize (Str) <= sizeof (Buffer)); + // + // Assume the case of input string is mixed + // + OutCaseFlag = FAT_CASE_MIXED; + // + // Lower case a copy of the string, if it matches the + // original then the string is lower case + // + StrCpy (Buffer, Str); + FatStrLwr (Buffer); + if (StrCmp (Str, Buffer) == 0) { + OutCaseFlag = InCaseFlag; + } + // + // Upper case a copy of the string, if it matches the + // original then the string is upper case + // + StrCpy (Buffer, Str); + FatStrUpr (Buffer); + if (StrCmp (Str, Buffer) == 0) { + OutCaseFlag = 0; + } + + return OutCaseFlag; +} + +VOID +FatSetCaseFlag ( + IN FAT_DIRENT *DirEnt + ) +/*++ + +Routine Description: + + Set the caseflag value for the directory entry. + +Arguments: + + DirEnt - The logical directory entry whose caseflag value is to be set. + +Returns: + + None. + +--*/ +{ + CHAR16 LfnBuffer[FAT_MAIN_NAME_LEN + 1 + FAT_EXTEND_NAME_LEN + 1]; + CHAR16 *TempCharPtr; + CHAR16 *ExtendName; + CHAR16 *FileNameCharPtr; + UINT8 CaseFlag; + + ExtendName = NULL; + TempCharPtr = LfnBuffer; + FileNameCharPtr = DirEnt->FileString; + ASSERT (StrSize (DirEnt->FileString) <= sizeof (LfnBuffer)); + while ((*TempCharPtr = *FileNameCharPtr) != 0) { + if (*TempCharPtr == L'.') { + ExtendName = TempCharPtr; + } + + TempCharPtr++; + FileNameCharPtr++; + } + + CaseFlag = 0; + if (ExtendName != NULL) { + *ExtendName = 0; + ExtendName++; + CaseFlag = (UINT8)(CaseFlag | FatCheckNameCase (ExtendName, FAT_CASE_EXT_LOWER)); + } + + CaseFlag = (UINT8)(CaseFlag | FatCheckNameCase (LfnBuffer, FAT_CASE_NAME_LOWER)); + if ((CaseFlag & FAT_CASE_MIXED) == 0) { + // + // We just need one directory entry to store this file name entry + // + DirEnt->Entry.CaseFlag = CaseFlag; + } else { + // + // We need one extra directory entry to store the mixed case entry + // + DirEnt->Entry.CaseFlag = 0; + DirEnt->EntryCount++; + } +} + +VOID +FatGetFileNameViaCaseFlag ( + IN FAT_DIRENT *DirEnt, + OUT CHAR16 *FileString + ) +/*++ + +Routine Description: + + Convert the 8.3 ASCII fat name to cased Unicode string according to case flag. + +Arguments: + + DirEnt - The corresponding directory entry. + FileString - The output Unicode file name. + +Returns: + + None. + +--*/ +{ + UINT8 CaseFlag; + CHAR8 *File8Dot3Name; + CHAR16 TempExt[1 + FAT_EXTEND_NAME_LEN + 1]; + // + // Store file extension like ".txt" + // + CaseFlag = DirEnt->Entry.CaseFlag; + File8Dot3Name = DirEnt->Entry.FileName; + + FatNameToStr (File8Dot3Name, FAT_MAIN_NAME_LEN, CaseFlag & FAT_CASE_NAME_LOWER, FileString); + FatNameToStr (File8Dot3Name + FAT_MAIN_NAME_LEN, FAT_EXTEND_NAME_LEN, CaseFlag & FAT_CASE_EXT_LOWER, &TempExt[1]); + if (TempExt[1] != 0) { + TempExt[0] = L'.'; + StrCat (FileString, TempExt); + } +} + +UINT8 +FatCheckSum ( + IN CHAR8 *ShortNameString + ) +/*++ + +Routine Description: + + Get the Check sum for a short name. + +Arguments: + + ShortNameString - The short name for a file. + +Returns: + + Sum - UINT8 checksum. + +--*/ +{ + UINTN ShortNameLen; + UINT8 Sum; + Sum = 0; + for (ShortNameLen = FAT_NAME_LEN; ShortNameLen != 0; ShortNameLen--) { + Sum = (UINT8)(((Sum & 1) ? 0x80 : 0) + (Sum >> 1) + *ShortNameString++); + } + + return Sum; +} + +CHAR16 * +FatGetNextNameComponent ( + IN CHAR16 *Path, + OUT CHAR16 *Name + ) +/*++ + +Routine Description: + + Takes Path as input, returns the next name component + in Name, and returns the position after Name (e.g., the + start of the next name component) + +Arguments: + + Path - The path of one file. + Name - The next name component in Path. + +Returns: + + The position after Name in the Path + +--*/ +{ + while (*Path != 0 && *Path != PATH_NAME_SEPARATOR) { + *Name++ = *Path++; + } + *Name = 0; + // + // Get off of trailing path name separator + // + while (*Path == PATH_NAME_SEPARATOR) { + Path++; + } + + return Path; +} + +BOOLEAN +FatFileNameIsValid ( + IN CHAR16 *InputFileName, + OUT CHAR16 *OutputFileName + ) +/*++ + +Routine Description: + + Check whether the IFileName is valid long file name. If the IFileName is a valid + long file name, then we trim the possible leading blanks and leading/trailing dots. + the trimmed filename is stored in OutputFileName + +Arguments: + + InputFileName - The input file name. + OutputFileName - The output file name. + + +Returns: + + TRUE - The InputFileName is a valid long file name. + FALSE - The InputFileName is not a valid long file name. + +--*/ +{ + CHAR16 *TempNamePointer; + CHAR16 TempChar; + // + // Trim Leading blanks + // + while (*InputFileName == L' ') { + InputFileName++; + } + + TempNamePointer = OutputFileName; + while (*InputFileName != 0) { + *TempNamePointer++ = *InputFileName++; + } + // + // Trim Trailing blanks and dots + // + while (TempNamePointer > OutputFileName) { + TempChar = *(TempNamePointer - 1); + if (TempChar != L' ' && TempChar != L'.') { + break; + } + + TempNamePointer--; + } + + *TempNamePointer = 0; + + // + // Per FAT Spec the file name should meet the following criteria: + // C1. Length (FileLongName) <= 255 + // C2. Length (X:FileFullPath) <= 260 + // Here we check C1. + // + if (TempNamePointer - OutputFileName > EFI_FILE_STRING_LENGTH) { + return FALSE; + } + // + // See if there is any illegal characters within the name + // + do { + if (*OutputFileName < 0x20 || + *OutputFileName == '\"' || + *OutputFileName == '*' || + *OutputFileName == '/' || + *OutputFileName == ':' || + *OutputFileName == '<' || + *OutputFileName == '>' || + *OutputFileName == '?' || + *OutputFileName == '\\' || + *OutputFileName == '|' + ) { + return FALSE; + } + + OutputFileName++; + } while (*OutputFileName != 0); + return TRUE; +} diff --git a/FatPkg/EnhancedFatDxe/FileSpace.c b/FatPkg/EnhancedFatDxe/FileSpace.c new file mode 100644 index 0000000..461f961 --- /dev/null +++ b/FatPkg/EnhancedFatDxe/FileSpace.c @@ -0,0 +1,814 @@ +/*++ + +Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the Software +License Agreement which accompanies this distribution. + + +Module Name: + + FileSpace.c + +Abstract: + + Routines dealing with disk spaces and FAT table entries + +Revision History + +--*/ + +#include "Fat.h" + + +STATIC +VOID * +FatLoadFatEntry ( + IN FAT_VOLUME *Volume, + IN UINTN Index + ) +/*++ + +Routine Description: + + Get the FAT entry of the volume, which is identified with the Index. + +Arguments: + + Volume - FAT file system volume. + Index - The index of the FAT entry of the volume. + +Returns: + + The buffer of the FAT entry + +--*/ +{ + UINTN Pos; + EFI_STATUS Status; + + if (Index > (Volume->MaxCluster + 1)) { + Volume->FatEntryBuffer = (UINT32) -1; + return &Volume->FatEntryBuffer; + } + // + // Compute buffer position needed + // + switch (Volume->FatType) { + case FAT12: + Pos = FAT_POS_FAT12 (Index); + break; + + case FAT16: + Pos = FAT_POS_FAT16 (Index); + break; + + default: + Pos = FAT_POS_FAT32 (Index); + } + // + // Set the position and read the buffer + // + Volume->FatEntryPos = Volume->FatPos + Pos; + Status = FatDiskIo ( + Volume, + READ_FAT, + Volume->FatEntryPos, + Volume->FatEntrySize, + &Volume->FatEntryBuffer, + NULL + ); + if (EFI_ERROR (Status)) { + Volume->FatEntryBuffer = (UINT32) -1; + } + + return &Volume->FatEntryBuffer; +} + +STATIC +UINTN +FatGetFatEntry ( + IN FAT_VOLUME *Volume, + IN UINTN Index + ) +/*++ + +Routine Description: + + Get the FAT entry value of the volume, which is identified with the Index. + +Arguments: + + Volume - FAT file system volume. + Index - The index of the FAT entry of the volume. + +Returns: + + The value of the FAT entry. + +--*/ +{ + VOID *Pos; + UINT8 *E12; + UINT16 *E16; + UINT32 *E32; + UINTN Accum; + + Pos = FatLoadFatEntry (Volume, Index); + + if (Index > (Volume->MaxCluster + 1)) { + return (UINTN) -1; + } + + switch (Volume->FatType) { + case FAT12: + E12 = Pos; + Accum = E12[0] | (E12[1] << 8); + Accum = FAT_ODD_CLUSTER_FAT12 (Index) ? (Accum >> 4) : (Accum & FAT_CLUSTER_MASK_FAT12); + Accum = Accum | ((Accum >= FAT_CLUSTER_SPECIAL_FAT12) ? FAT_CLUSTER_SPECIAL_EXT : 0); + break; + + case FAT16: + E16 = Pos; + Accum = *E16; + Accum = Accum | ((Accum >= FAT_CLUSTER_SPECIAL_FAT16) ? FAT_CLUSTER_SPECIAL_EXT : 0); + break; + + default: + E32 = Pos; + Accum = *E32 & FAT_CLUSTER_MASK_FAT32; + Accum = Accum | ((Accum >= FAT_CLUSTER_SPECIAL_FAT32) ? FAT_CLUSTER_SPECIAL_EXT : 0); + } + + return Accum; +} + +STATIC +EFI_STATUS +FatSetFatEntry ( + IN FAT_VOLUME *Volume, + IN UINTN Index, + IN UINTN Value + ) +/*++ + +Routine Description: + + Set the FAT entry value of the volume, which is identified with the Index. + +Arguments: + + Volume - FAT file system volume. + Index - The index of the FAT entry of the volume. + Value - The new value of the FAT entry. + +Returns: + + EFI_SUCCESS - Set the new FAT entry value sucessfully. + EFI_VOLUME_CORRUPTED - The FAT type of the volume is error. + other - An error occurred when operation the FAT entries. + +--*/ +{ + VOID *Pos; + UINT8 *E12; + UINT16 *E16; + UINT32 *E32; + UINTN Accum; + EFI_STATUS Status; + UINTN OriginalVal; + + if (Index < FAT_MIN_CLUSTER) { + return EFI_VOLUME_CORRUPTED; + } + + OriginalVal = FatGetFatEntry (Volume, Index); + if (Value == FAT_CLUSTER_FREE && OriginalVal != FAT_CLUSTER_FREE) { + Volume->FatInfoSector.FreeInfo.ClusterCount += 1; + if (Index < Volume->FatInfoSector.FreeInfo.NextCluster) { + Volume->FatInfoSector.FreeInfo.NextCluster = (UINT32) Index; + } + } else if (Value != FAT_CLUSTER_FREE && OriginalVal == FAT_CLUSTER_FREE) { + if (Volume->FatInfoSector.FreeInfo.ClusterCount != 0) { + Volume->FatInfoSector.FreeInfo.ClusterCount -= 1; + } + } + // + // Make sure the entry is in memory + // + Pos = FatLoadFatEntry (Volume, Index); + + // + // Update the value + // + switch (Volume->FatType) { + case FAT12: + E12 = Pos; + Accum = E12[0] | (E12[1] << 8); + Value = Value & FAT_CLUSTER_MASK_FAT12; + + if (FAT_ODD_CLUSTER_FAT12 (Index)) { + Accum = (Value << 4) | (Accum & 0xF); + } else { + Accum = Value | (Accum & FAT_CLUSTER_UNMASK_FAT12); + } + + E12[0] = (UINT8) (Accum & 0xFF); + E12[1] = (UINT8) (Accum >> 8); + break; + + case FAT16: + E16 = Pos; + *E16 = (UINT16) Value; + break; + + default: + E32 = Pos; + *E32 = (*E32 & FAT_CLUSTER_UNMASK_FAT32) | (UINT32) (Value & FAT_CLUSTER_MASK_FAT32); + } + // + // If the volume's dirty bit is not set, set it now + // + if (!Volume->FatDirty && Volume->FatType != FAT12) { + Volume->FatDirty = TRUE; + FatAccessVolumeDirty (Volume, WRITE_FAT, &Volume->DirtyValue); + } + // + // Write the updated fat entry value to the volume + // The fat is the first fat, and other fat will be in sync + // when the FAT cache flush back. + // + Status = FatDiskIo ( + Volume, + WRITE_FAT, + Volume->FatEntryPos, + Volume->FatEntrySize, + &Volume->FatEntryBuffer, + NULL + ); + return Status; +} + +STATIC +EFI_STATUS +FatFreeClusters ( + IN FAT_VOLUME *Volume, + IN UINTN Cluster + ) +/*++ + +Routine Description: + + Free the cluster clain. + +Arguments: + + Volume - FAT file system volume. + Cluster - The first cluster of cluster chain. + +Returns: + + EFI_SUCCESS - The cluster chain is freed successfully. + EFI_VOLUME_CORRUPTED - There are errors in the file's clusters. + +--*/ +{ + UINTN LastCluster; + + while (!FAT_END_OF_FAT_CHAIN (Cluster)) { + if (Cluster == FAT_CLUSTER_FREE || Cluster >= FAT_CLUSTER_SPECIAL) { + + DEBUG ((EFI_D_INIT | EFI_D_ERROR, "FatShrinkEof: cluster chain corrupt\n")); + return EFI_VOLUME_CORRUPTED; + } + + LastCluster = Cluster; + Cluster = FatGetFatEntry (Volume, Cluster); + FatSetFatEntry (Volume, LastCluster, FAT_CLUSTER_FREE); + } + + return EFI_SUCCESS; +} + +STATIC +UINTN +FatAllocateCluster ( + IN FAT_VOLUME *Volume + ) +/*++ + +Routine Description: + + Allocate a free cluster and return the cluster index. + +Arguments: + + Volume - FAT file system volume. + +Returns: + + The index of the free cluster + +--*/ +{ + UINTN Cluster; + + // + // Start looking at FatFreePos for the next unallocated cluster + // + if (Volume->DiskError) { + return (UINTN) FAT_CLUSTER_LAST; + } + + for (;;) { + // + // If the end of the list, return no available cluster + // + if (Volume->FatInfoSector.FreeInfo.NextCluster > (Volume->MaxCluster + 1)) { + if (Volume->FreeInfoValid && 0 < (INT32) (Volume->FatInfoSector.FreeInfo.ClusterCount)) { + Volume->FreeInfoValid = FALSE; + } + + FatComputeFreeInfo (Volume); + if (Volume->FatInfoSector.FreeInfo.NextCluster > (Volume->MaxCluster + 1)) { + return (UINTN) FAT_CLUSTER_LAST; + } + } + + Cluster = FatGetFatEntry (Volume, Volume->FatInfoSector.FreeInfo.NextCluster); + if (Cluster == FAT_CLUSTER_FREE) { + break; + } + // + // Try the next cluster + // + Volume->FatInfoSector.FreeInfo.NextCluster += 1; + } + + Cluster = Volume->FatInfoSector.FreeInfo.NextCluster; + Volume->FatInfoSector.FreeInfo.NextCluster += 1; + return Cluster; +} + +STATIC +UINTN +FatSizeToClusters ( + IN FAT_VOLUME *Volume, + IN UINTN Size + ) +/*++ + +Routine Description: + + Count the number of clusters given a size + +Arguments: + + Volume - The file system volume. + Size - The size in bytes. + +Returns: + + The number of the clusters. + +--*/ +{ + UINTN Clusters; + + Clusters = Size >> Volume->ClusterAlignment; + if ((Size & (Volume->ClusterSize - 1)) > 0) { + Clusters += 1; + } + + return Clusters; +} + +EFI_STATUS +FatShrinkEof ( + IN FAT_OFILE *OFile + ) +/*++ + +Routine Description: + + Shrink the end of the open file base on the file size. + +Arguments: + + OFile - The open file. + +Returns: + + EFI_SUCCESS - Shrinked sucessfully. + EFI_VOLUME_CORRUPTED - There are errors in the file's clusters. + +--*/ +{ + FAT_VOLUME *Volume; + UINTN NewSize; + UINTN CurSize; + UINTN Cluster; + UINTN LastCluster; + + Volume = OFile->Volume; + ASSERT_VOLUME_LOCKED (Volume); + + NewSize = FatSizeToClusters (Volume, OFile->FileSize); + + // + // Find the address of the last cluster + // + Cluster = OFile->FileCluster; + LastCluster = FAT_CLUSTER_FREE; + + if (NewSize != 0) { + + for (CurSize = 0; CurSize < NewSize; CurSize++) { + if (Cluster == FAT_CLUSTER_FREE || Cluster >= FAT_CLUSTER_SPECIAL) { + + DEBUG ((EFI_D_INIT | EFI_D_ERROR, "FatShrinkEof: cluster chain corrupt\n")); + return EFI_VOLUME_CORRUPTED; + } + + LastCluster = Cluster; + Cluster = FatGetFatEntry (Volume, Cluster); + } + + FatSetFatEntry (Volume, LastCluster, (UINTN) FAT_CLUSTER_LAST); + + } else { + // + // Check to see if the file is already completely truncated + // + if (Cluster == FAT_CLUSTER_FREE) { + return EFI_SUCCESS; + } + // + // The file is being completely truncated. + // + OFile->FileCluster = FAT_CLUSTER_FREE; + } + // + // Set CurrentCluster == FileCluster + // to force a recalculation of Position related stuffs + // + OFile->FileCurrentCluster = OFile->FileCluster; + OFile->FileLastCluster = LastCluster; + OFile->Dirty = TRUE; + // + // Free the remaining cluster chain + // + return FatFreeClusters (Volume, Cluster); +} + +EFI_STATUS +FatGrowEof ( + IN FAT_OFILE *OFile, + IN UINT64 NewSizeInBytes + ) +/*++ + +Routine Description: + + Grow the end of the open file base on the NewSizeInBytes. + +Arguments: + + OFile - The open file. + NewSizeInBytes - The new size in bytes of the open file. + +Returns: + + EFI_SUCCESS - The file is grown sucessfully. + EFI_UNSUPPORTED - The file size is larger than 4GB. + EFI_VOLUME_CORRUPTED - There are errors in the files' clusters. + EFI_VOLUME_FULL - The volume is full and can not grow the file. + +--*/ +{ + FAT_VOLUME *Volume; + EFI_STATUS Status; + UINTN Cluster; + UINTN CurSize; + UINTN NewSize; + UINTN LastCluster; + UINTN NewCluster; + UINTN ClusterCount; + + // + // For FAT file system, the max file is 4GB. + // + if (NewSizeInBytes > 0x0FFFFFFFFL) { + return EFI_UNSUPPORTED; + } + + Volume = OFile->Volume; + ASSERT_VOLUME_LOCKED (Volume); + // + // If the file is already large enough, do nothing + // + CurSize = FatSizeToClusters (Volume, OFile->FileSize); + NewSize = FatSizeToClusters (Volume, (UINTN) NewSizeInBytes); + + if (CurSize < NewSize) { + // + // If we haven't found the files last cluster do it now + // + if ((OFile->FileCluster != 0) && (OFile->FileLastCluster == 0)) { + Cluster = OFile->FileCluster; + ClusterCount = 0; + + while (!FAT_END_OF_FAT_CHAIN (Cluster)) { + if (Cluster == FAT_CLUSTER_FREE || Cluster >= FAT_CLUSTER_SPECIAL) { + + DEBUG ( + (EFI_D_INIT | EFI_D_ERROR, + "FatGrowEof: cluster chain corrupt\n") + ); + Status = EFI_VOLUME_CORRUPTED; + goto Done; + } + + ClusterCount++; + OFile->FileLastCluster = Cluster; + Cluster = FatGetFatEntry (Volume, Cluster); + } + + if (ClusterCount != CurSize) { + DEBUG ( + (EFI_D_INIT | EFI_D_ERROR, + "FatGrowEof: cluster chain size does not match file size\n") + ); + Status = EFI_VOLUME_CORRUPTED; + goto Done; + } + + } + // + // Loop until we've allocated enough space + // + LastCluster = OFile->FileLastCluster; + + while (CurSize < NewSize) { + NewCluster = FatAllocateCluster (Volume); + if (FAT_END_OF_FAT_CHAIN (NewCluster)) { + if (LastCluster != FAT_CLUSTER_FREE) { + FatSetFatEntry (Volume, LastCluster, (UINTN) FAT_CLUSTER_LAST); + OFile->FileLastCluster = LastCluster; + } + + Status = EFI_VOLUME_FULL; + goto Done; + } + + if (LastCluster != 0) { + FatSetFatEntry (Volume, LastCluster, NewCluster); + } else { + OFile->FileCluster = NewCluster; + OFile->FileCurrentCluster = NewCluster; + } + + LastCluster = NewCluster; + CurSize += 1; + } + // + // Terminate the cluster list + // + FatSetFatEntry (Volume, LastCluster, (UINTN) FAT_CLUSTER_LAST); + OFile->FileLastCluster = LastCluster; + } + + OFile->FileSize = (UINTN) NewSizeInBytes; + OFile->Dirty = TRUE; + return EFI_SUCCESS; + +Done: + FatShrinkEof (OFile); + return Status; +} + +EFI_STATUS +FatOFilePosition ( + IN FAT_OFILE *OFile, + IN UINTN Position, + IN UINTN PosLimit + ) +/*++ + +Routine Description: + + Seek OFile to requested position, and calculate the number of + consecutive clusters from the position in the file + +Arguments: + + OFile - The open file. + Position - The file's position which will be accessed. + PosLimit - The maximum length current reading/writing may access + +Returns: + + EFI_SUCCESS - Set the info successfully. + EFI_VOLUME_CORRUPTED - Cluster chain corrupt. + +--*/ +{ + FAT_VOLUME *Volume; + UINTN ClusterSize; + UINTN Cluster; + UINTN StartPos; + UINTN Run; + + Volume = OFile->Volume; + ClusterSize = Volume->ClusterSize; + + ASSERT_VOLUME_LOCKED (Volume); + + // + // If this is the fixed root dir, then compute it's position + // from it's fixed info in the fat bpb + // + if (OFile->IsFixedRootDir) { + OFile->PosDisk = Volume->RootPos + Position; + Run = OFile->FileSize - Position; + } else { + // + // Run the file's cluster chain to find the current position + // If possible, run from the current cluster rather than + // start from beginning + // Assumption: OFile->Position is always consistent with + // OFile->FileCurrentCluster. + // OFile->Position is not modified outside this function; + // OFile->FileCurrentCluster is modified outside this function + // to be the same as OFile->FileCluster + // when OFile->FileCluster is updated, so make a check of this + // and invalidate the original OFile->Position in this case + // + Cluster = OFile->FileCurrentCluster; + StartPos = OFile->Position; + if (Position < StartPos || OFile->FileCluster == Cluster) { + StartPos = 0; + Cluster = OFile->FileCluster; + } + + while (StartPos + ClusterSize <= Position) { + StartPos += ClusterSize; + if (Cluster == FAT_CLUSTER_FREE || (Cluster >= FAT_CLUSTER_SPECIAL)) { + DEBUG ((EFI_D_INIT | EFI_D_ERROR, "FatOFilePosition:"" cluster chain corrupt\n")); + return EFI_VOLUME_CORRUPTED; + } + + Cluster = FatGetFatEntry (Volume, Cluster); + } + + if (Cluster < FAT_MIN_CLUSTER) { + return EFI_VOLUME_CORRUPTED; + } + + OFile->PosDisk = Volume->FirstClusterPos + + LShiftU64 (Cluster - FAT_MIN_CLUSTER, Volume->ClusterAlignment) + + Position - StartPos; + OFile->FileCurrentCluster = Cluster; + OFile->Position = StartPos; + + // + // Compute the number of consecutive clusters in the file + // + Run = StartPos + ClusterSize - Position; + if (!FAT_END_OF_FAT_CHAIN (Cluster)) { + while ((FatGetFatEntry (Volume, Cluster) == Cluster + 1) && Run < PosLimit) { + Run += ClusterSize; + Cluster += 1; + } + } + } + + OFile->PosRem = Run; + return EFI_SUCCESS; +} + +UINTN +FatPhysicalDirSize ( + IN FAT_VOLUME *Volume, + IN UINTN Cluster + ) +/*++ + +Routine Description: + + Get the size of directory of the open file + +Arguments: + + Volume - The File System Volume. + Cluster - The Starting cluster. + +Returns: + + The physical size of the file starting at the input cluster, if there is error in the + cluster chain, the return value is 0. + +--*/ +{ + UINTN Size; + ASSERT_VOLUME_LOCKED (Volume); + // + // Run the cluster chain for the OFile + // + Size = 0; + // + // N.B. ".." directories on some media do not contain a starting + // cluster. In the case of "." or ".." we don't need the size anyway. + // + if (Cluster != 0) { + while (!FAT_END_OF_FAT_CHAIN (Cluster)) { + if (Cluster == FAT_CLUSTER_FREE || Cluster >= FAT_CLUSTER_SPECIAL) { + DEBUG ( + (EFI_D_INIT | EFI_D_ERROR, + "FATDirSize: cluster chain corrupt\n") + ); + return 0; + } + + Size += Volume->ClusterSize; + Cluster = FatGetFatEntry (Volume, Cluster); + } + } + + return Size; +} + +UINT64 +FatPhysicalFileSize ( + IN FAT_VOLUME *Volume, + IN UINTN RealSize + ) +/*++ + +Routine Description: + + Get the physical size of a file on the disk. + +Arguments: + + Volume - The file system volume. + RealSize - The real size of a file. + +Returns: + + The physical size of a file on the disk. + +--*/ +{ + UINTN ClusterSizeMask; + UINT64 PhysicalSize; + ClusterSizeMask = Volume->ClusterSize - 1; + PhysicalSize = (RealSize + ClusterSizeMask) & (~((UINT64) ClusterSizeMask)); + return PhysicalSize; +} + +VOID +FatComputeFreeInfo ( + IN FAT_VOLUME *Volume + ) +/*++ + +Routine Description: + + Update the free cluster info of FatInfoSector of the volume. + +Arguments: + + Volume - FAT file system volume. + +Returns: + + None. + +--*/ +{ + UINTN Index; + + // + // If we don't have valid info, compute it now + // + if (!Volume->FreeInfoValid) { + + Volume->FreeInfoValid = TRUE; + Volume->FatInfoSector.FreeInfo.ClusterCount = 0; + for (Index = Volume->MaxCluster + 1; Index >= FAT_MIN_CLUSTER; Index--) { + if (Volume->DiskError) { + break; + } + + if (FatGetFatEntry (Volume, Index) == FAT_CLUSTER_FREE) { + Volume->FatInfoSector.FreeInfo.ClusterCount += 1; + Volume->FatInfoSector.FreeInfo.NextCluster = (UINT32) Index; + } + } + + Volume->FatInfoSector.Signature = FAT_INFO_SIGNATURE; + Volume->FatInfoSector.InfoBeginSignature = FAT_INFO_BEGIN_SIGNATURE; + Volume->FatInfoSector.InfoEndSignature = FAT_INFO_END_SIGNATURE; + } +} diff --git a/FatPkg/EnhancedFatDxe/Flush.c b/FatPkg/EnhancedFatDxe/Flush.c new file mode 100644 index 0000000..1bb4c3d --- /dev/null +++ b/FatPkg/EnhancedFatDxe/Flush.c @@ -0,0 +1,536 @@ +/*++ + +Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the Software +License Agreement which accompanies this distribution. + + +Module Name: + + flush.c + +Abstract: + + Routines that check references and flush OFiles + +Revision History + +--*/ + +#include "Fat.h" + +EFI_STATUS +EFIAPI +FatFlushEx ( + IN EFI_FILE_PROTOCOL *FHand, + IN EFI_FILE_IO_TOKEN *Token + ) +/*++ + +Routine Description: + + Flushes all data associated with the file handle. + +Arguments: + + FHand - Handle to file to flush. + Token - A pointer to the token associated with the transaction. + +Returns: + + EFI_SUCCESS - Flushed the file successfully. + EFI_WRITE_PROTECTED - The volume is read only. + EFI_ACCESS_DENIED - The file is read only. + Others - Flushing of the file failed. + +--*/ +{ + FAT_IFILE *IFile; + FAT_OFILE *OFile; + FAT_VOLUME *Volume; + EFI_STATUS Status; + FAT_TASK *Task; + + IFile = IFILE_FROM_FHAND (FHand); + OFile = IFile->OFile; + Volume = OFile->Volume; + Task = NULL; + + // + // If the file has a permanent error, return it + // + if (EFI_ERROR (OFile->Error)) { + return OFile->Error; + } + + if (Volume->ReadOnly) { + return EFI_WRITE_PROTECTED; + } + // + // If read only, return error + // + if (IFile->ReadOnly) { + return EFI_ACCESS_DENIED; + } + + if (Token == NULL) { + FatWaitNonblockingTask (IFile); + } else { + // + // Caller shouldn't call the non-blocking interfaces if the low layer doesn't support DiskIo2. + // But if it calls, the below check can avoid crash. + // + if (FHand->Revision < EFI_FILE_PROTOCOL_REVISION2) { + return EFI_UNSUPPORTED; + } + Task = FatCreateTask (IFile, Token); + if (Task == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } + + // + // Flush the OFile + // + FatAcquireLock (); + Status = FatOFileFlush (OFile); + Status = FatCleanupVolume (OFile->Volume, OFile, Status, Task); + FatReleaseLock (); + + if (Token != NULL) { + if (!EFI_ERROR (Status)) { + Status = FatQueueTask (IFile, Task); + } else { + FatDestroyTask (Task); + } + } + + return Status; +} + +EFI_STATUS +EFIAPI +FatFlush ( + IN EFI_FILE_PROTOCOL *FHand + ) +/*++ + +Routine Description: + + Flushes all data associated with the file handle. + +Arguments: + + FHand - Handle to file to flush. + +Returns: + + EFI_SUCCESS - Flushed the file successfully. + EFI_WRITE_PROTECTED - The volume is read only. + EFI_ACCESS_DENIED - The file is read only. + Others - Flushing of the file failed. + +--*/ +{ + return FatFlushEx (FHand, NULL); +} + +EFI_STATUS +EFIAPI +FatClose ( + IN EFI_FILE_PROTOCOL *FHand + ) +/*++ + +Routine Description: + + Flushes & Closes the file handle. + +Arguments: + + FHand - Handle to the file to delete. + +Returns: + + EFI_SUCCESS - Closed the file successfully. + +--*/ +{ + FAT_IFILE *IFile; + FAT_OFILE *OFile; + FAT_VOLUME *Volume; + + IFile = IFILE_FROM_FHAND (FHand); + OFile = IFile->OFile; + Volume = OFile->Volume; + + // + // Lock the volume + // + FatAcquireLock (); + + // + // Close the file instance handle + // + FatIFileClose (IFile); + + // + // Done. Unlock the volume + // + FatCleanupVolume (Volume, OFile, EFI_SUCCESS, NULL); + FatReleaseLock (); + + // + // Close always succeed + // + return EFI_SUCCESS; +} + +EFI_STATUS +FatIFileClose ( + FAT_IFILE *IFile + ) +/*++ + +Routine Description: + + Close the open file instance. + +Arguments: + + IFile - Open file instance. + +Returns: + + EFI_SUCCESS - Closed the file successfully. + +--*/ +{ + FAT_OFILE *OFile; + FAT_VOLUME *Volume; + + OFile = IFile->OFile; + Volume = OFile->Volume; + + ASSERT_VOLUME_LOCKED (Volume); + + FatWaitNonblockingTask (IFile); + + // + // Remove the IFile struct + // + RemoveEntryList (&IFile->Link); + + // + // Add the OFile to the check reference list + // + if (OFile->CheckLink.ForwardLink == NULL) { + InsertHeadList (&Volume->CheckRef, &OFile->CheckLink); + } + // + // Done. Free the open instance structure + // + FreePool (IFile); + return EFI_SUCCESS; +} + +EFI_STATUS +FatOFileFlush ( + IN FAT_OFILE *OFile + ) +/*++ + +Routine Description: + + Flush the data associated with an open file. + In this implementation, only last Mod/Access time is updated. + +Arguments: + + OFile - The open file. + +Returns: + + EFI_SUCCESS - The OFile is flushed successfully. + Others - An error occurred when flushing this OFile. + +--*/ +{ + EFI_STATUS Status; + FAT_OFILE *Parent; + FAT_DIRENT *DirEnt; + FAT_DATE_TIME FatNow; + + // + // Flush each entry up the tree while dirty + // + do { + // + // If the file has a permanant error, then don't write any + // of its data to the device (may be from different media) + // + if (EFI_ERROR (OFile->Error)) { + return OFile->Error; + } + + Parent = OFile->Parent; + DirEnt = OFile->DirEnt; + if (OFile->Dirty) { + // + // Update the last modification time + // + FatGetCurrentFatTime (&FatNow); + CopyMem (&DirEnt->Entry.FileLastAccess, &FatNow.Date, sizeof (FAT_DATE)); + if (!OFile->PreserveLastModification) { + FatGetCurrentFatTime (&DirEnt->Entry.FileModificationTime); + } + + OFile->PreserveLastModification = FALSE; + if (OFile->Archive) { + DirEnt->Entry.Attributes |= FAT_ATTRIBUTE_ARCHIVE; + OFile->Archive = FALSE; + } + // + // Write the directory entry + // + if (Parent != NULL && !DirEnt->Invalid) { + // + // Write the OFile's directory entry + // + Status = FatStoreDirEnt (Parent, DirEnt); + if (EFI_ERROR (Status)) { + return Status; + } + } + + OFile->Dirty = FALSE; + } + // + // Check the parent + // + OFile = Parent; + } while (OFile != NULL); + return EFI_SUCCESS; +} + +BOOLEAN +FatCheckOFileRef ( + IN FAT_OFILE *OFile + ) +/*++ + +Routine Description: + + Check the references of the OFile. + If the OFile (that is checked) is no longer + referenced, then it is freed. + +Arguments: + + OFile - The OFile to be checked. + +Returns: + + TRUE - The OFile is not referenced and freed. + FALSE - The OFile is kept. + +--*/ +{ + // + // If the OFile is on the check ref list, remove it + // + if (OFile->CheckLink.ForwardLink != NULL) { + RemoveEntryList (&OFile->CheckLink); + OFile->CheckLink.ForwardLink = NULL; + } + + FatOFileFlush (OFile); + // + // Are there any references to this OFile? + // + if (!IsListEmpty (&OFile->Opens) || !IsListEmpty (&OFile->ChildHead)) { + // + // The OFile cannot be freed + // + return FALSE; + } + // + // Free the Ofile + // + FatCloseDirEnt (OFile->DirEnt); + return TRUE; +} + +STATIC +VOID +FatCheckVolumeRef ( + IN FAT_VOLUME *Volume + ) +/*++ + +Routine Description: + + Check the references of all open files on the volume. + Any open file (that is checked) that is no longer + referenced, is freed - and it's parent open file + is then referenced checked. + +Arguments: + + Volume - The volume to check the pending open file list. + +Returns: + + None + +--*/ +{ + FAT_OFILE *OFile; + FAT_OFILE *Parent; + + // + // Check all files on the pending check list + // + while (!IsListEmpty (&Volume->CheckRef)) { + // + // Start with the first file listed + // + Parent = OFILE_FROM_CHECKLINK (Volume->CheckRef.ForwardLink); + // + // Go up the tree cleaning up any un-referenced OFiles + // + while (Parent != NULL) { + OFile = Parent; + Parent = OFile->Parent; + if (!FatCheckOFileRef (OFile)) { + break; + } + } + } +} + +EFI_STATUS +FatCleanupVolume ( + IN FAT_VOLUME *Volume, + IN FAT_OFILE *OFile, + IN EFI_STATUS EfiStatus, + IN FAT_TASK *Task + ) +/*++ + +Routine Description: + + Set error status for a specific OFile, reference checking the volume. + If volume is already marked as invalid, and all resources are freed + after reference checking, the file system protocol is uninstalled and + the volume structure is freed. + +Arguments: + + Volume - the Volume that is to be reference checked and unlocked. + OFile - the OFile whose permanent error code is to be set. + EfiStatus - error code to be set. + +Returns: + + EFI_SUCCESS - Clean up the volume successfully. + Others - Cleaning up of the volume is failed. + +--*/ +{ + EFI_STATUS Status; + // + // Flag the OFile + // + if (OFile != NULL) { + FatSetVolumeError (OFile, EfiStatus); + } + // + // Clean up any dangling OFiles that don't have IFiles + // we don't check return status here because we want the + // volume be cleaned up even the volume is invalid. + // + FatCheckVolumeRef (Volume); + if (Volume->Valid) { + // + // Update the free hint info. Volume->FreeInfoPos != 0 + // indicates this a FAT32 volume + // + if (Volume->FreeInfoValid && Volume->FatDirty && Volume->FreeInfoPos) { + Status = FatDiskIo (Volume, WRITE_DISK, Volume->FreeInfoPos, sizeof (FAT_INFO_SECTOR), &Volume->FatInfoSector, Task); + if (EFI_ERROR (Status)) { + return Status; + } + } + // + // Update that the volume is not dirty + // + if (Volume->FatDirty && Volume->FatType != FAT12) { + Volume->FatDirty = FALSE; + Status = FatAccessVolumeDirty (Volume, WRITE_FAT, &Volume->NotDirtyValue); + if (EFI_ERROR (Status)) { + return Status; + } + } + // + // Flush all dirty cache entries to disk + // + Status = FatVolumeFlushCache (Volume, Task); + if (EFI_ERROR (Status)) { + return Status; + } + } + // + // If the volume is cleared , remove it. + // The only time volume be invalidated is in DriverBindingStop. + // + if (Volume->Root == NULL && !Volume->Valid) { + // + // Free the volume structure + // + FatFreeVolume (Volume); + } + + return EfiStatus; +} + +VOID +FatSetVolumeError ( + IN FAT_OFILE *OFile, + IN EFI_STATUS Status + ) +/*++ + +Routine Description: + + Set the OFile and its child OFile with the error Status + +Arguments: + + OFile - The OFile whose permanent error code is to be set. + Status - Error code to be set. + +Returns: + + None + +--*/ +{ + LIST_ENTRY *Link; + FAT_OFILE *ChildOFile; + + // + // If this OFile doesn't already have an error, set one + // + if (!EFI_ERROR (OFile->Error)) { + OFile->Error = Status; + } + // + // Set the error on each child OFile + // + for (Link = OFile->ChildHead.ForwardLink; Link != &OFile->ChildHead; Link = Link->ForwardLink) { + ChildOFile = OFILE_FROM_CHILDLINK (Link); + FatSetVolumeError (ChildOFile, Status); + } +} diff --git a/FatPkg/EnhancedFatDxe/Hash.c b/FatPkg/EnhancedFatDxe/Hash.c new file mode 100644 index 0000000..d186e35 --- /dev/null +++ b/FatPkg/EnhancedFatDxe/Hash.c @@ -0,0 +1,214 @@ +/*++ + +Copyright (c) 2005 - 2014, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the Software +License Agreement which accompanies this distribution. + + +Module Name: + + Hash.c + +Abstract: + + Hash table operations + +Revision History + +--*/ + +#include "Fat.h" + +STATIC +UINT32 +FatHashLongName ( + IN CHAR16 *LongNameString + ) +/*++ + +Routine Description: + + Get hash value for long name. + +Arguments: + + LongNameString - The long name string to be hashed. + +Returns: + + HashValue. + +--*/ +{ + UINT32 HashValue; + CHAR16 UpCasedLongFileName[EFI_PATH_STRING_LENGTH]; + StrnCpy (UpCasedLongFileName, LongNameString, EFI_PATH_STRING_LENGTH - 1); + UpCasedLongFileName[EFI_PATH_STRING_LENGTH - 1] = L'\0'; + FatStrUpr (UpCasedLongFileName); + gBS->CalculateCrc32 (UpCasedLongFileName, StrSize (UpCasedLongFileName), &HashValue); + return (HashValue & HASH_TABLE_MASK); +} + +STATIC +UINT32 +FatHashShortName ( + IN CHAR8 *ShortNameString + ) +/*++ + +Routine Description: + + Get hash value for short name. + +Arguments: + + ShortNameString - The short name string to be hashed. + +Returns: + + HashValue + +--*/ +{ + UINT32 HashValue; + gBS->CalculateCrc32 (ShortNameString, FAT_NAME_LEN, &HashValue); + return (HashValue & HASH_TABLE_MASK); +} + +FAT_DIRENT ** +FatLongNameHashSearch ( + IN FAT_ODIR *ODir, + IN CHAR16 *LongNameString + ) +/*++ + +Routine Description: + + Search the long name hash table for the directory entry. + +Arguments: + + ODir - The directory to be searched. + LongNameString - The long name string to search. + +Returns: + + The previous long name hash node of the directory entry. + +--*/ +{ + FAT_DIRENT **PreviousHashNode; + for (PreviousHashNode = &ODir->LongNameHashTable[FatHashLongName (LongNameString)]; + *PreviousHashNode != NULL; + PreviousHashNode = &(*PreviousHashNode)->LongNameForwardLink + ) { + if (FatStriCmp (LongNameString, (*PreviousHashNode)->FileString) == 0) { + break; + } + } + + return PreviousHashNode; +} + +FAT_DIRENT ** +FatShortNameHashSearch ( + IN FAT_ODIR *ODir, + IN CHAR8 *ShortNameString + ) +/*++ + +Routine Description: + + Search the short name hash table for the directory entry. + +Arguments: + + ODir - The directory to be searched. + ShortNameString - The short name string to search. + +Returns: + + The previous short name hash node of the directory entry. + +--*/ +{ + FAT_DIRENT **PreviousHashNode; + for (PreviousHashNode = &ODir->ShortNameHashTable[FatHashShortName (ShortNameString)]; + *PreviousHashNode != NULL; + PreviousHashNode = &(*PreviousHashNode)->ShortNameForwardLink + ) { + if (CompareMem (ShortNameString, (*PreviousHashNode)->Entry.FileName, FAT_NAME_LEN) == 0) { + break; + } + } + + return PreviousHashNode; +} + +VOID +FatInsertToHashTable ( + IN FAT_ODIR *ODir, + IN FAT_DIRENT *DirEnt + ) +/*++ + +Routine Description: + + Insert directory entry to hash table. + +Arguments: + + ODir - The parent directory. + DirEnt - The directory entry node. + +Returns: + + None. + +--*/ +{ + FAT_DIRENT **HashTable; + UINT32 HashTableIndex; + + // + // Insert hash table index for short name + // + HashTableIndex = FatHashShortName (DirEnt->Entry.FileName); + HashTable = ODir->ShortNameHashTable; + DirEnt->ShortNameForwardLink = HashTable[HashTableIndex]; + HashTable[HashTableIndex] = DirEnt; + // + // Insert hash table index for long name + // + HashTableIndex = FatHashLongName (DirEnt->FileString); + HashTable = ODir->LongNameHashTable; + DirEnt->LongNameForwardLink = HashTable[HashTableIndex]; + HashTable[HashTableIndex] = DirEnt; +} + +VOID +FatDeleteFromHashTable ( + IN FAT_ODIR *ODir, + IN FAT_DIRENT *DirEnt + ) +/*++ + +Routine Description: + + Delete directory entry from hash table. + +Arguments: + + ODir - The parent directory. + DirEnt - The directory entry node. + +Returns: + + None. + +--*/ +{ + *FatShortNameHashSearch (ODir, DirEnt->Entry.FileName) = DirEnt->ShortNameForwardLink; + *FatLongNameHashSearch (ODir, DirEnt->FileString) = DirEnt->LongNameForwardLink; +} diff --git a/FatPkg/EnhancedFatDxe/Info.c b/FatPkg/EnhancedFatDxe/Info.c new file mode 100644 index 0000000..d10e27c --- /dev/null +++ b/FatPkg/EnhancedFatDxe/Info.c @@ -0,0 +1,619 @@ +/*++ + +Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the Software +License Agreement which accompanies this distribution. + + +Module Name: + + Info.c + +Abstract: + + Routines dealing with setting/getting file/volume info + +Revision History + +--*/ + +#include "Fat.h" + +EFI_STATUS +FatGetVolumeInfo ( + IN FAT_VOLUME *Volume, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ); + +EFI_STATUS +FatSetVolumeInfo ( + IN FAT_VOLUME *Volume, + IN OUT UINTN BufferSize, + OUT VOID *Buffer + ); + +EFI_STATUS +FatSetOrGetInfo ( + IN BOOLEAN IsSet, + IN EFI_FILE_PROTOCOL *FHand, + IN EFI_GUID *Type, + IN OUT UINTN *BufferSize, + IN OUT VOID *Buffer + ); + +EFI_STATUS +FatGetFileInfo ( + IN FAT_OFILE *OFile, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Get the open file's info into Buffer. + +Arguments: + + OFile - The open file. + BufferSize - Size of Buffer. + Buffer - Buffer containing file info. + +Returns: + + EFI_SUCCESS - Get the file info successfully. + EFI_BUFFER_TOO_SMALL - The buffer is too small. + +--*/ +{ + return FatGetDirEntInfo (OFile->Volume, OFile->DirEnt, BufferSize, Buffer); +} + +EFI_STATUS +FatGetVolumeInfo ( + IN FAT_VOLUME *Volume, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Get the volume's info into Buffer. + +Arguments: + + Volume - FAT file system volume. + BufferSize - Size of Buffer. + Buffer - Buffer containing volume info. + +Returns: + + EFI_SUCCESS - Get the volume info successfully. + EFI_BUFFER_TOO_SMALL - The buffer is too small. + +--*/ +{ + UINTN Size; + UINTN NameSize; + UINTN ResultSize; + CHAR16 Name[FAT_NAME_LEN + 1]; + EFI_STATUS Status; + EFI_FILE_SYSTEM_INFO *Info; + UINT8 ClusterAlignment; + + Size = SIZE_OF_EFI_FILE_SYSTEM_INFO; + Status = FatGetVolumeEntry (Volume, Name); + NameSize = StrSize (Name); + ResultSize = Size + NameSize; + ClusterAlignment = Volume->ClusterAlignment; + + // + // If we don't have valid info, compute it now + // + FatComputeFreeInfo (Volume); + + Status = EFI_BUFFER_TOO_SMALL; + if (*BufferSize >= ResultSize) { + Status = EFI_SUCCESS; + + Info = Buffer; + ZeroMem (Info, SIZE_OF_EFI_FILE_SYSTEM_INFO); + + Info->Size = ResultSize; + Info->ReadOnly = Volume->ReadOnly; + Info->BlockSize = (UINT32) Volume->ClusterSize; + Info->VolumeSize = LShiftU64 (Volume->MaxCluster, ClusterAlignment); + Info->FreeSpace = LShiftU64 ( + Volume->FatInfoSector.FreeInfo.ClusterCount, + ClusterAlignment + ); + CopyMem ((CHAR8 *) Buffer + Size, Name, NameSize); + } + + *BufferSize = ResultSize; + return Status; +} + +EFI_STATUS +FatGetVolumeLabelInfo ( + IN FAT_VOLUME *Volume, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Get the volume's label info into Buffer. + +Arguments: + + Volume - FAT file system volume. + BufferSize - Size of Buffer. + Buffer - Buffer containing volume's label info. + +Returns: + + EFI_SUCCESS - Get the volume's label info successfully. + EFI_BUFFER_TOO_SMALL - The buffer is too small. + +--*/ +{ + UINTN Size; + UINTN NameSize; + UINTN ResultSize; + CHAR16 Name[FAT_NAME_LEN + 1]; + EFI_STATUS Status; + + Size = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL; + Status = FatGetVolumeEntry (Volume, Name); + NameSize = StrSize (Name); + ResultSize = Size + NameSize; + + Status = EFI_BUFFER_TOO_SMALL; + if (*BufferSize >= ResultSize) { + Status = EFI_SUCCESS; + CopyMem ((CHAR8 *) Buffer + Size, Name, NameSize); + } + + *BufferSize = ResultSize; + return Status; +} + +EFI_STATUS +FatSetVolumeInfo ( + IN FAT_VOLUME *Volume, + IN UINTN BufferSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Set the volume's info. + +Arguments: + + Volume - FAT file system volume. + BufferSize - Size of Buffer. + Buffer - Buffer containing the new volume info. + +Returns: + + EFI_SUCCESS - Set the volume info successfully. + EFI_BAD_BUFFER_SIZE - The buffer size is error. + EFI_WRITE_PROTECTED - The volume is read only. + other - An error occurred when operation the disk. + +--*/ +{ + EFI_FILE_SYSTEM_INFO *Info; + + Info = (EFI_FILE_SYSTEM_INFO *) Buffer; + + if (BufferSize < SIZE_OF_EFI_FILE_SYSTEM_INFO + 2 || Info->Size > BufferSize) { + return EFI_BAD_BUFFER_SIZE; + } + + return FatSetVolumeEntry (Volume, Info->VolumeLabel); +} + +EFI_STATUS +FatSetVolumeLabelInfo ( + IN FAT_VOLUME *Volume, + IN UINTN BufferSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Set the volume's label info + +Arguments: + + Volume - FAT file system volume. + BufferSize - Size of Buffer. + Buffer - Buffer containing the new volume label info. + +Returns: + + EFI_SUCCESS - Set the volume label info successfully. + EFI_WRITE_PROTECTED - The disk is write protected. + EFI_BAD_BUFFER_SIZE - The buffer size is error. + other - An error occurred when operation the disk. + +--*/ +{ + EFI_FILE_SYSTEM_VOLUME_LABEL *Info; + + Info = (EFI_FILE_SYSTEM_VOLUME_LABEL *) Buffer; + + if (BufferSize < SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL + 2) { + return EFI_BAD_BUFFER_SIZE; + } + + return FatSetVolumeEntry (Volume, Info->VolumeLabel); +} + +EFI_STATUS +FatSetFileInfo ( + IN FAT_VOLUME *Volume, + IN FAT_IFILE *IFile, + IN FAT_OFILE *OFile, + IN UINTN BufferSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Set the file info. + +Arguments: + + Volume - FAT file system volume. + IFile - The instance of the open file. + OFile - The open file. + BufferSize - Size of Buffer. + Buffer - Buffer containing the new file info. + +Returns: + + EFI_SUCCESS - Set the file info successfully. + EFI_ACCESS_DENIED - It is the root directory + or the directory attribute bit can not change + or try to change a directory size + or something else. + EFI_UNSUPPORTED - The new file size is larger than 4GB. + EFI_WRITE_PROTECTED - The disk is write protected. + EFI_BAD_BUFFER_SIZE - The buffer size is error. + EFI_INVALID_PARAMETER - The time info or attributes info is error. + EFI_OUT_OF_RESOURCES - Can not allocate new memory. + EFI_VOLUME_CORRUPTED - The volume is corrupted. + other - An error occurred when operation the disk. + +--*/ +{ + EFI_STATUS Status; + EFI_FILE_INFO *NewInfo; + FAT_OFILE *DotOFile; + FAT_OFILE *Parent; + CHAR16 NewFileName[EFI_PATH_STRING_LENGTH]; + EFI_TIME ZeroTime; + FAT_DIRENT *DirEnt; + FAT_DIRENT *TempDirEnt; + UINT8 NewAttribute; + BOOLEAN ReadOnly; + + ZeroMem (&ZeroTime, sizeof (EFI_TIME)); + Parent = OFile->Parent; + DirEnt = OFile->DirEnt; + // + // If this is the root directory, we can't make any updates + // + if (Parent == NULL) { + return EFI_ACCESS_DENIED; + } + // + // Make sure there's a valid input buffer + // + NewInfo = Buffer; + if (BufferSize < SIZE_OF_EFI_FILE_INFO + 2 || NewInfo->Size > BufferSize) { + return EFI_BAD_BUFFER_SIZE; + } + + ReadOnly = (BOOLEAN)(IFile->ReadOnly || (DirEnt->Entry.Attributes & EFI_FILE_READ_ONLY)); + // + // if a zero time is specified, then the original time is preserved + // + if (CompareMem (&ZeroTime, &NewInfo->CreateTime, sizeof (EFI_TIME)) != 0) { + if (!FatIsValidTime (&NewInfo->CreateTime)) { + return EFI_INVALID_PARAMETER; + } + + if (!ReadOnly) { + FatEfiTimeToFatTime (&NewInfo->CreateTime, &DirEnt->Entry.FileCreateTime); + } + } + + if (CompareMem (&ZeroTime, &NewInfo->ModificationTime, sizeof (EFI_TIME)) != 0) { + if (!FatIsValidTime (&NewInfo->ModificationTime)) { + return EFI_INVALID_PARAMETER; + } + + if (!ReadOnly) { + FatEfiTimeToFatTime (&NewInfo->ModificationTime, &DirEnt->Entry.FileModificationTime); + } + + OFile->PreserveLastModification = TRUE; + } + + if (NewInfo->Attribute & (~EFI_FILE_VALID_ATTR)) { + return EFI_INVALID_PARAMETER; + } + + NewAttribute = (UINT8) NewInfo->Attribute; + // + // Can not change the directory attribute bit + // + if ((NewAttribute ^ DirEnt->Entry.Attributes) & EFI_FILE_DIRECTORY) { + return EFI_ACCESS_DENIED; + } + // + // Set the current attributes even if the IFile->ReadOnly is TRUE + // + DirEnt->Entry.Attributes = (UINT8) ((DirEnt->Entry.Attributes &~EFI_FILE_VALID_ATTR) | NewAttribute); + // + // Open the filename and see if it refers to an existing file + // + Status = FatLocateOFile (&Parent, NewInfo->FileName, DirEnt->Entry.Attributes, NewFileName); + if (EFI_ERROR (Status)) { + return Status; + } + + if (*NewFileName != 0) { + // + // File was not found. We do not allow rename of the current directory if + // there are open files below the current directory + // + if (!IsListEmpty (&OFile->ChildHead) || Parent == OFile) { + return EFI_ACCESS_DENIED; + } + + if (ReadOnly) { + return EFI_ACCESS_DENIED; + } + + Status = FatRemoveDirEnt (OFile->Parent, DirEnt); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Create new dirent + // + Status = FatCreateDirEnt (Parent, NewFileName, DirEnt->Entry.Attributes, &TempDirEnt); + if (EFI_ERROR (Status)) { + return Status; + } + + FatCloneDirEnt (TempDirEnt, DirEnt); + FatFreeDirEnt (DirEnt); + DirEnt = TempDirEnt; + DirEnt->OFile = OFile; + OFile->DirEnt = DirEnt; + OFile->Parent = Parent; + RemoveEntryList (&OFile->ChildLink); + InsertHeadList (&Parent->ChildHead, &OFile->ChildLink); + // + // If this is a directory, synchronize its dot directory entry + // + if (OFile->ODir != NULL) { + // + // Syncronize its dot entry + // + FatResetODirCursor (OFile); + ASSERT (OFile->Parent != NULL); + for (DotOFile = OFile; DotOFile != OFile->Parent->Parent; DotOFile = DotOFile->Parent) { + Status = FatGetNextDirEnt (OFile, &DirEnt); + if (EFI_ERROR (Status) || DirEnt == NULL || !FatIsDotDirEnt (DirEnt)) { + return EFI_VOLUME_CORRUPTED; + } + + FatCloneDirEnt (DirEnt, DotOFile->DirEnt); + Status = FatStoreDirEnt (OFile, DirEnt); + if (EFI_ERROR (Status)) { + return Status; + } + } + } + // + // If the file is renamed, we should append the ARCHIVE attribute + // + OFile->Archive = TRUE; + } else if (Parent != OFile) { + // + // filename is to a different filename that already exists + // + return EFI_ACCESS_DENIED; + } + // + // If the file size has changed, apply it + // + if (NewInfo->FileSize != OFile->FileSize) { + if (OFile->ODir != NULL || ReadOnly) { + // + // If this is a directory or the file is read only, we can't change the file size + // + return EFI_ACCESS_DENIED; + } + + if (NewInfo->FileSize > OFile->FileSize) { + Status = FatExpandOFile (OFile, NewInfo->FileSize); + } else { + Status = FatTruncateOFile (OFile, (UINTN) NewInfo->FileSize); + } + + if (EFI_ERROR (Status)) { + return Status; + } + + FatUpdateDirEntClusterSizeInfo (OFile); + } + + OFile->Dirty = TRUE; + return FatOFileFlush (OFile); +} + +EFI_STATUS +FatSetOrGetInfo ( + IN BOOLEAN IsSet, + IN EFI_FILE_PROTOCOL *FHand, + IN EFI_GUID *Type, + IN OUT UINTN *BufferSize, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Set or Get the some types info of the file into Buffer + +Arguments: + + IsSet - TRUE:The access is set, else is get + FHand - The handle of file + Type - The type of the info + BufferSize - Size of Buffer + Buffer - Buffer containing volume info + +Returns: + + EFI_SUCCESS - Get the info successfully + EFI_DEVICE_ERROR - Can not find the OFile for the file + +--*/ +{ + FAT_IFILE *IFile; + FAT_OFILE *OFile; + FAT_VOLUME *Volume; + EFI_STATUS Status; + + IFile = IFILE_FROM_FHAND (FHand); + OFile = IFile->OFile; + Volume = OFile->Volume; + + Status = OFile->Error; + if (Status == EFI_NOT_FOUND) { + return EFI_DEVICE_ERROR; + } + + FatWaitNonblockingTask (IFile); + + FatAcquireLock (); + + // + // Verify the file handle isn't in an error state + // + if (!EFI_ERROR (Status)) { + // + // Get the proper information based on the request + // + Status = EFI_UNSUPPORTED; + if (IsSet) { + if (CompareGuid (Type, &gEfiFileInfoGuid)) { + Status = Volume->ReadOnly ? EFI_WRITE_PROTECTED : FatSetFileInfo (Volume, IFile, OFile, *BufferSize, Buffer); + } + + if (CompareGuid (Type, &gEfiFileSystemInfoGuid)) { + Status = Volume->ReadOnly ? EFI_WRITE_PROTECTED : FatSetVolumeInfo (Volume, *BufferSize, Buffer); + } + + if (CompareGuid (Type, &gEfiFileSystemVolumeLabelInfoIdGuid)) { + Status = Volume->ReadOnly ? EFI_WRITE_PROTECTED : FatSetVolumeLabelInfo (Volume, *BufferSize, Buffer); + } + } else { + if (CompareGuid (Type, &gEfiFileInfoGuid)) { + Status = FatGetFileInfo (OFile, BufferSize, Buffer); + } + + if (CompareGuid (Type, &gEfiFileSystemInfoGuid)) { + Status = FatGetVolumeInfo (Volume, BufferSize, Buffer); + } + + if (CompareGuid (Type, &gEfiFileSystemVolumeLabelInfoIdGuid)) { + Status = FatGetVolumeLabelInfo (Volume, BufferSize, Buffer); + } + } + } + + Status = FatCleanupVolume (Volume, NULL, Status, NULL); + + FatReleaseLock (); + return Status; +} + +EFI_STATUS +EFIAPI +FatGetInfo ( + IN EFI_FILE_PROTOCOL *FHand, + IN EFI_GUID *Type, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Get the some types info of the file into Buffer. + +Arguments: + + FHand - The handle of file. + Type - The type of the info. + BufferSize - Size of Buffer. + Buffer - Buffer containing volume info. + +Returns: + + EFI_SUCCESS - Get the info successfully. + EFI_DEVICE_ERROR - Can not find the OFile for the file. + +--*/ +{ + return FatSetOrGetInfo (FALSE, FHand, Type, BufferSize, Buffer); +} + +EFI_STATUS +EFIAPI +FatSetInfo ( + IN EFI_FILE_PROTOCOL *FHand, + IN EFI_GUID *Type, + IN UINTN BufferSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Set the some types info of the file into Buffer. + +Arguments: + + FHand - The handle of file. + Type - The type of the info. + BufferSize - Size of Buffer + Buffer - Buffer containing volume info. + +Returns: + + EFI_SUCCESS - Set the info successfully. + EFI_DEVICE_ERROR - Can not find the OFile for the file. + +--*/ +{ + return FatSetOrGetInfo (TRUE, FHand, Type, &BufferSize, Buffer); +} diff --git a/FatPkg/EnhancedFatDxe/Init.c b/FatPkg/EnhancedFatDxe/Init.c new file mode 100644 index 0000000..0958f95 --- /dev/null +++ b/FatPkg/EnhancedFatDxe/Init.c @@ -0,0 +1,414 @@ +/*++ + +Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the Software +License Agreement which accompanies this distribution. + + +Module Name: + + Init.c + +Abstract: + + Initialization routines + +--*/ + +#include "Fat.h" + +EFI_STATUS +FatAllocateVolume ( + IN EFI_HANDLE Handle, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN EFI_DISK_IO2_PROTOCOL *DiskIo2, + IN EFI_BLOCK_IO_PROTOCOL *BlockIo + ) +/*++ + +Routine Description: + + Allocates volume structure, detects FAT file system, installs protocol, + and initialize cache. + +Arguments: + + Handle - The handle of parent device. + DiskIo - The DiskIo of parent device. + BlockIo - The BlockIo of parent devicel + +Returns: + + EFI_SUCCESS - Allocate a new volume successfully. + EFI_OUT_OF_RESOURCES - Can not allocate the memory. + Others - Allocating a new volume failed. + +--*/ +{ + EFI_STATUS Status; + FAT_VOLUME *Volume; + + // + // Allocate a volume structure + // + Volume = AllocateZeroPool (sizeof (FAT_VOLUME)); + if (Volume == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Initialize the structure + // + Volume->Signature = FAT_VOLUME_SIGNATURE; + Volume->Handle = Handle; + Volume->DiskIo = DiskIo; + Volume->DiskIo2 = DiskIo2; + Volume->BlockIo = BlockIo; + Volume->MediaId = BlockIo->Media->MediaId; + Volume->ReadOnly = BlockIo->Media->ReadOnly; + Volume->VolumeInterface.Revision = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION; + Volume->VolumeInterface.OpenVolume = FatOpenVolume; + InitializeListHead (&Volume->CheckRef); + InitializeListHead (&Volume->DirCacheList); + // + // Initialize Root Directory entry + // + Volume->RootDirEnt.FileString = Volume->RootFileString; + Volume->RootDirEnt.Entry.Attributes = FAT_ATTRIBUTE_DIRECTORY; + // + // Check to see if there's a file system on the volume + // + Status = FatOpenDevice (Volume); + if (EFI_ERROR (Status)) { + goto Done; + } + // + // Initialize cache + // + Status = FatInitializeDiskCache (Volume); + if (EFI_ERROR (Status)) { + goto Done; + } + // + // Install our protocol interfaces on the device's handle + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &Volume->Handle, + &gEfiSimpleFileSystemProtocolGuid, + &Volume->VolumeInterface, + NULL + ); + if (EFI_ERROR (Status)) { + goto Done; + } + // + // Volume installed + // + DEBUG ((EFI_D_INIT, "Installed Fat filesystem on %p\n", Handle)); + Volume->Valid = TRUE; + +Done: + if (EFI_ERROR (Status)) { + FatFreeVolume (Volume); + } + + return Status; +} + +EFI_STATUS +FatAbandonVolume ( + IN FAT_VOLUME *Volume + ) +/*++ + +Routine Description: + + Called by FatDriverBindingStop(), Abandon the volume. + +Arguments: + + Volume - The volume to be abandoned. + +Returns: + + EFI_SUCCESS - Abandoned the volume successfully. + Others - Can not uninstall the protocol interfaces. + +--*/ +{ + EFI_STATUS Status; + BOOLEAN LockedByMe; + + // + // Uninstall the protocol interface. + // + if (Volume->Handle != NULL) { + Status = gBS->UninstallMultipleProtocolInterfaces ( + Volume->Handle, + &gEfiSimpleFileSystemProtocolGuid, + &Volume->VolumeInterface, + NULL + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + + LockedByMe = FALSE; + + // + // Acquire the lock. + // If the caller has already acquired the lock (which + // means we are in the process of some Fat operation), + // we can not acquire again. + // + Status = FatAcquireLockOrFail (); + if (!EFI_ERROR (Status)) { + LockedByMe = TRUE; + } + // + // The volume is still being used. Hence, set error flag for all OFiles still in + // use. In two cases, we could get here. One is EFI_MEDIA_CHANGED, the other is + // EFI_NO_MEDIA. + // + if (Volume->Root != NULL) { + FatSetVolumeError ( + Volume->Root, + Volume->BlockIo->Media->MediaPresent ? EFI_MEDIA_CHANGED : EFI_NO_MEDIA + ); + } + + Volume->Valid = FALSE; + + // + // Release the lock. + // If locked by me, this means DriverBindingStop is NOT + // called within an on-going Fat operation, so we should + // take responsibility to cleanup and free the volume. + // Otherwise, the DriverBindingStop is called within an on-going + // Fat operation, we shouldn't check reference, so just let outer + // FatCleanupVolume do the task. + // + if (LockedByMe) { + FatCleanupVolume (Volume, NULL, EFI_SUCCESS, NULL); + FatReleaseLock (); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +FatOpenDevice ( + IN OUT FAT_VOLUME *Volume + ) +/*++ + +Routine Description: + + Detects FAT file system on Disk and set relevant fields of Volume + +Arguments: + + Volume - The volume structure. + +Returns: + + EFI_SUCCESS - The Fat File System is detected successfully + EFI_UNSUPPORTED - The volume is not FAT file system. + EFI_VOLUME_CORRUPTED - The volume is corrupted. + +--*/ +{ + EFI_STATUS Status; + UINT32 BlockSize; + UINT32 DirtyMask; + EFI_DISK_IO_PROTOCOL *DiskIo; + FAT_BOOT_SECTOR FatBs; + FAT_VOLUME_TYPE FatType; + UINTN RootDirSectors; + UINTN FatLba; + UINTN RootLba; + UINTN FirstClusterLba; + UINTN Sectors; + UINTN SectorsPerFat; + UINT8 SectorsPerClusterAlignment; + UINT8 BlockAlignment; + + // + // Read the FAT_BOOT_SECTOR BPB info + // This is the only part of FAT code that uses parent DiskIo, + // Others use FatDiskIo which utilizes a Cache. + // + DiskIo = Volume->DiskIo; + Status = DiskIo->ReadDisk (DiskIo, Volume->MediaId, 0, sizeof (FatBs), &FatBs); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_INIT, "FatOpenDevice: read of part_lba failed %r\n", Status)); + return Status; + } + + FatType = FatUndefined; + + // + // Use LargeSectors if Sectors is 0 + // + Sectors = FatBs.FatBsb.Sectors; + if (Sectors == 0) { + Sectors = FatBs.FatBsb.LargeSectors; + } + + SectorsPerFat = FatBs.FatBsb.SectorsPerFat; + if (SectorsPerFat == 0) { + SectorsPerFat = FatBs.FatBse.Fat32Bse.LargeSectorsPerFat; + FatType = FAT32; + } + // + // Is boot sector a fat sector? + // (Note that so far we only know if the sector is FAT32 or not, we don't + // know if the sector is Fat16 or Fat12 until later when we can compute + // the volume size) + // + if (FatBs.FatBsb.ReservedSectors == 0 || FatBs.FatBsb.NumFats == 0 || Sectors == 0) { + return EFI_UNSUPPORTED; + } + + if ((FatBs.FatBsb.SectorSize & (FatBs.FatBsb.SectorSize - 1)) != 0) { + return EFI_UNSUPPORTED; + } + + BlockAlignment = (UINT8) HighBitSet32 (FatBs.FatBsb.SectorSize); + if (BlockAlignment > MAX_BLOCK_ALIGNMENT || BlockAlignment < MIN_BLOCK_ALIGNMENT) { + return EFI_UNSUPPORTED; + } + + if ((FatBs.FatBsb.SectorsPerCluster & (FatBs.FatBsb.SectorsPerCluster - 1)) != 0) { + return EFI_UNSUPPORTED; + } + + SectorsPerClusterAlignment = (UINT8) HighBitSet32 (FatBs.FatBsb.SectorsPerCluster); + if (SectorsPerClusterAlignment > MAX_SECTORS_PER_CLUSTER_ALIGNMENT) { + return EFI_UNSUPPORTED; + } + + if (FatBs.FatBsb.Media <= 0xf7 && + FatBs.FatBsb.Media != 0xf0 && + FatBs.FatBsb.Media != 0x00 && + FatBs.FatBsb.Media != 0x01 + ) { + return EFI_UNSUPPORTED; + } + // + // Initialize fields the volume information for this FatType + // + if (FatType != FAT32) { + if (FatBs.FatBsb.RootEntries == 0) { + return EFI_UNSUPPORTED; + } + // + // Unpack fat12, fat16 info + // + Volume->RootEntries = FatBs.FatBsb.RootEntries; + } else { + // + // If this is fat32, refuse to mount mirror-disabled volumes + // + if ((SectorsPerFat == 0 || FatBs.FatBse.Fat32Bse.FsVersion != 0) || (FatBs.FatBse.Fat32Bse.ExtendedFlags & 0x80)) { + return EFI_UNSUPPORTED; + } + // + // Unpack fat32 info + // + Volume->RootCluster = FatBs.FatBse.Fat32Bse.RootDirFirstCluster; + } + + Volume->NumFats = FatBs.FatBsb.NumFats; + // + // Compute some fat locations + // + BlockSize = FatBs.FatBsb.SectorSize; + RootDirSectors = ((Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY)) + (BlockSize - 1)) / BlockSize; + + FatLba = FatBs.FatBsb.ReservedSectors; + RootLba = FatBs.FatBsb.NumFats * SectorsPerFat + FatLba; + FirstClusterLba = RootLba + RootDirSectors; + + Volume->FatPos = FatLba * BlockSize; + Volume->FatSize = SectorsPerFat * BlockSize; + + Volume->VolumeSize = LShiftU64 (Sectors, BlockAlignment); + Volume->RootPos = LShiftU64 (RootLba, BlockAlignment); + Volume->FirstClusterPos = LShiftU64 (FirstClusterLba, BlockAlignment); + Volume->MaxCluster = (Sectors - FirstClusterLba) >> SectorsPerClusterAlignment; + Volume->ClusterAlignment = (UINT8)(BlockAlignment + SectorsPerClusterAlignment); + Volume->ClusterSize = (UINTN)1 << (Volume->ClusterAlignment); + + // + // If this is not a fat32, determine if it's a fat16 or fat12 + // + if (FatType != FAT32) { + if (Volume->MaxCluster >= FAT_MAX_FAT16_CLUSTER) { + return EFI_VOLUME_CORRUPTED; + } + + FatType = Volume->MaxCluster < FAT_MAX_FAT12_CLUSTER ? FAT12 : FAT16; + // + // fat12 & fat16 fat-entries are 2 bytes + // + Volume->FatEntrySize = sizeof (UINT16); + DirtyMask = FAT16_DIRTY_MASK; + } else { + if (Volume->MaxCluster < FAT_MAX_FAT16_CLUSTER) { + return EFI_VOLUME_CORRUPTED; + } + // + // fat32 fat-entries are 4 bytes + // + Volume->FatEntrySize = sizeof (UINT32); + DirtyMask = FAT32_DIRTY_MASK; + } + // + // Get the DirtyValue and NotDirtyValue + // We should keep the initial value as the NotDirtyValue + // in case the volume is dirty already + // + if (FatType != FAT12) { + Status = FatAccessVolumeDirty (Volume, READ_DISK, &Volume->NotDirtyValue); + if (EFI_ERROR (Status)) { + return Status; + } + + Volume->DirtyValue = Volume->NotDirtyValue & DirtyMask; + } + // + // If present, read the fat hint info + // + if (FatType == FAT32) { + Volume->FreeInfoPos = FatBs.FatBse.Fat32Bse.FsInfoSector * BlockSize; + if (FatBs.FatBse.Fat32Bse.FsInfoSector != 0) { + FatDiskIo (Volume, READ_DISK, Volume->FreeInfoPos, sizeof (FAT_INFO_SECTOR), &Volume->FatInfoSector, NULL); + if (Volume->FatInfoSector.Signature == FAT_INFO_SIGNATURE && + Volume->FatInfoSector.InfoBeginSignature == FAT_INFO_BEGIN_SIGNATURE && + Volume->FatInfoSector.InfoEndSignature == FAT_INFO_END_SIGNATURE && + Volume->FatInfoSector.FreeInfo.ClusterCount <= Volume->MaxCluster + ) { + Volume->FreeInfoValid = TRUE; + } + } + } + // + // Just make up a FreeInfo.NextCluster for use by allocate cluster + // + if (FAT_MIN_CLUSTER > Volume->FatInfoSector.FreeInfo.NextCluster || + Volume->FatInfoSector.FreeInfo.NextCluster > Volume->MaxCluster + 1 + ) { + Volume->FatInfoSector.FreeInfo.NextCluster = FAT_MIN_CLUSTER; + } + // + // We are now defining FAT Type + // + Volume->FatType = FatType; + ASSERT (FatType != FatUndefined); + + return EFI_SUCCESS; +} diff --git a/FatPkg/EnhancedFatDxe/Misc.c b/FatPkg/EnhancedFatDxe/Misc.c new file mode 100644 index 0000000..aa012d8 --- /dev/null +++ b/FatPkg/EnhancedFatDxe/Misc.c @@ -0,0 +1,737 @@ +/*++ + +Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the Software +License Agreement which accompanies this distribution. + + +Module Name: + + Misc.c + +Abstract: + + Miscellaneous functions + +Revision History + +--*/ + +#include "Fat.h" + +FAT_TASK * +FatCreateTask ( + FAT_IFILE *IFile, + EFI_FILE_IO_TOKEN *Token + ) +/*++ + +Routine Description: + + Create the task + +Arguments: + + IFile - The instance of the open file. + Token - A pointer to the token associated with the transaction. + +Return: + FAT_TASK * - Return the task instance. +**/ +{ + FAT_TASK *Task; + + Task = AllocateZeroPool (sizeof (*Task)); + if (Task != NULL) { + Task->Signature = FAT_TASK_SIGNATURE; + Task->IFile = IFile; + Task->FileIoToken = Token; + InitializeListHead (&Task->Subtasks); + InitializeListHead (&Task->Link); + } + return Task; +} + +VOID +FatDestroyTask ( + FAT_TASK *Task + ) +/*++ + +Routine Description: + + Destroy the task + +Arguments: + + Task - The task to be destroyed. +**/ +{ + LIST_ENTRY *Link; + FAT_SUBTASK *Subtask; + + Link = GetFirstNode (&Task->Subtasks); + while (!IsNull (&Task->Subtasks, Link)) { + Subtask = CR (Link, FAT_SUBTASK, Link, FAT_SUBTASK_SIGNATURE); + Link = FatDestroySubtask (Subtask); + } + FreePool (Task); +} + +VOID +FatWaitNonblockingTask ( + FAT_IFILE *IFile + ) +/*++ + +Routine Description: + + Wait all non-blocking requests complete. + +Arguments: + + IFile - The instance of the open file. +**/ +{ + BOOLEAN TaskQueueEmpty; + + do { + EfiAcquireLock (&FatTaskLock); + TaskQueueEmpty = IsListEmpty (&IFile->Tasks); + EfiReleaseLock (&FatTaskLock); + } while (!TaskQueueEmpty); +} + +LIST_ENTRY * +FatDestroySubtask ( + FAT_SUBTASK *Subtask + ) +/*++ + +Routine Description: + + Remove the subtask from subtask list. + +Arguments: + + Subtask - The subtask to be removed. + +Returns: + + LIST_ENTRY * - The next node in the list. + +--*/ +{ + LIST_ENTRY *Link; + + gBS->CloseEvent (Subtask->DiskIo2Token.Event); + + Link = RemoveEntryList (&Subtask->Link); + FreePool (Subtask); + + return Link; +} + +EFI_STATUS +FatQueueTask ( + IN FAT_IFILE *IFile, + IN FAT_TASK *Task + ) +/*++ + +Routine Description: + + Execute the task + +Arguments: + + IFile - The instance of the open file. + Task - The task to be executed. + +Returns: + + EFI_SUCCESS - The task was executed sucessfully. + other - An error occurred when executing the task. + +--*/ +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + FAT_SUBTASK *Subtask; + + // + // Sometimes the Task doesn't contain any subtasks, signal the event directly. + // + if (IsListEmpty (&Task->Subtasks)) { + Task->FileIoToken->Status = EFI_SUCCESS; + gBS->SignalEvent (Task->FileIoToken->Event); + FreePool (Task); + return EFI_SUCCESS; + } + + EfiAcquireLock (&FatTaskLock); + InsertTailList (&IFile->Tasks, &Task->Link); + EfiReleaseLock (&FatTaskLock); + + Status = EFI_SUCCESS; + for ( Link = GetFirstNode (&Task->Subtasks) + ; !IsNull (&Task->Subtasks, Link) + ; Link = GetNextNode (&Task->Subtasks, Link) + ) { + Subtask = CR (Link, FAT_SUBTASK, Link, FAT_SUBTASK_SIGNATURE); + if (Subtask->Write) { + + Status = IFile->OFile->Volume->DiskIo2->WriteDiskEx ( + IFile->OFile->Volume->DiskIo2, + IFile->OFile->Volume->MediaId, + Subtask->Offset, + &Subtask->DiskIo2Token, + Subtask->BufferSize, + Subtask->Buffer + ); + } else { + Status = IFile->OFile->Volume->DiskIo2->ReadDiskEx ( + IFile->OFile->Volume->DiskIo2, + IFile->OFile->Volume->MediaId, + Subtask->Offset, + &Subtask->DiskIo2Token, + Subtask->BufferSize, + Subtask->Buffer + ); + } + if (EFI_ERROR (Status)) { + break; + } + } + + if (EFI_ERROR (Status)) { + EfiAcquireLock (&FatTaskLock); + // + // Remove all the remaining subtasks when failure. + // We shouldn't remove all the tasks because the non-blocking requests have + // been submitted and cannot be canceled. + // + while (!IsNull (&Task->Subtasks, Link)) { + Subtask = CR (Link, FAT_SUBTASK, Link, FAT_SUBTASK_SIGNATURE); + Link = FatDestroySubtask (Subtask); + } + + if (IsListEmpty (&Task->Subtasks)) { + RemoveEntryList (&Task->Link); + FreePool (Task); + } else { + // + // If one or more subtasks have been already submitted, set FileIoToken + // to NULL so that the callback won't signal the event. + // + Task->FileIoToken = NULL; + } + + EfiReleaseLock (&FatTaskLock); + } + + return Status; +} + +EFI_STATUS +FatAccessVolumeDirty ( + IN FAT_VOLUME *Volume, + IN IO_MODE IoMode, + IN VOID *DirtyValue + ) +/*++ + +Routine Description: + + Set the volume as dirty or not + +Arguments: + + Volume - FAT file system volume. + IoMode - The access mode. + DirtyValue - Set the volume as dirty or not. + +Returns: + + EFI_SUCCESS - Set the new FAT entry value sucessfully. + other - An error occurred when operation the FAT entries. + +--*/ +{ + UINTN WriteCount; + + WriteCount = Volume->FatEntrySize; + return FatDiskIo (Volume, IoMode, Volume->FatPos + WriteCount, WriteCount, DirtyValue, NULL); +} + +/** + Invoke a notification event + + @param Event Event whose notification function is being invoked. + @param Context The pointer to the notification function's context, + which is implementation-dependent. + +**/ +VOID +EFIAPI +FatOnAccessComplete ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + + Invoke a notification event + case #1. some subtasks are not completed when the FatOpenEx checks the Task->Subtasks + - sets Task->SubtaskCollected so callback to signal the event and free the task. + case #2. all subtasks are completed when the FatOpenEx checks the Task->Subtasks + - FatOpenEx signal the event and free the task. +Arguments: + + Event - Event whose notification function is being invoked. + Context - The pointer to the notification function's context, + which is implementation-dependent. + +--*/ +{ + EFI_STATUS Status; + FAT_SUBTASK *Subtask; + FAT_TASK *Task; + + // + // Avoid someone in future breaks the below assumption. + // + ASSERT (EfiGetCurrentTpl () == FatTaskLock.Tpl); + + Subtask = (FAT_SUBTASK *) Context; + Task = Subtask->Task; + Status = Subtask->DiskIo2Token.TransactionStatus; + + ASSERT (Task->Signature == FAT_TASK_SIGNATURE); + ASSERT (Subtask->Signature == FAT_SUBTASK_SIGNATURE); + + // + // Remove the task unconditionally + // + FatDestroySubtask (Subtask); + + // + // Task->FileIoToken is NULL which means the task will be ignored (just recycle the subtask and task memory). + // + if (Task->FileIoToken != NULL) { + if (IsListEmpty (&Task->Subtasks) || EFI_ERROR (Status)) { + Task->FileIoToken->Status = Status; + gBS->SignalEvent (Task->FileIoToken->Event); + // + // Mark Task->FileIoToken to NULL so that the subtasks belonging to the task will be ignored. + // + Task->FileIoToken = NULL; + } + } + + if (IsListEmpty (&Task->Subtasks)) { + RemoveEntryList (&Task->Link); + FreePool (Task); + } +} + +EFI_STATUS +FatDiskIo ( + IN FAT_VOLUME *Volume, + IN IO_MODE IoMode, + IN UINT64 Offset, + IN UINTN BufferSize, + IN OUT VOID *Buffer, + IN FAT_TASK *Task + ) +/*++ + +Routine Description: + + General disk access function + +Arguments: + + Volume - FAT file system volume. + IoMode - The access mode (disk read/write or cache access). + Offset - The starting byte offset to read from. + BufferSize - Size of Buffer. + Buffer - Buffer containing read data. + +Returns: + + EFI_SUCCESS - The operation is performed successfully. + EFI_VOLUME_CORRUPTED - The accesss is + Others - The status of read/write the disk + +--*/ +{ + EFI_STATUS Status; + EFI_DISK_IO_PROTOCOL *DiskIo; + EFI_DISK_READ IoFunction; + FAT_SUBTASK *Subtask; + + // + // Verify the IO is in devices range + // + Status = EFI_VOLUME_CORRUPTED; + if (Offset + BufferSize <= Volume->VolumeSize) { + if (CACHE_ENABLED (IoMode)) { + // + // Access cache + // + Status = FatAccessCache (Volume, CACHE_TYPE (IoMode), RAW_ACCESS (IoMode), Offset, BufferSize, Buffer, Task); + } else { + // + // Access disk directly + // + if (Task == NULL) { + // + // Blocking access + // + DiskIo = Volume->DiskIo; + IoFunction = (IoMode == READ_DISK) ? DiskIo->ReadDisk : DiskIo->WriteDisk; + Status = IoFunction (DiskIo, Volume->MediaId, Offset, BufferSize, Buffer); + } else { + // + // Non-blocking access + // + Subtask = AllocateZeroPool (sizeof (*Subtask)); + if (Subtask == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } else { + Subtask->Signature = FAT_SUBTASK_SIGNATURE; + Subtask->Task = Task; + Subtask->Write = (BOOLEAN) (IoMode == WRITE_DISK); + Subtask->Offset = Offset; + Subtask->Buffer = Buffer; + Subtask->BufferSize = BufferSize; + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + FatOnAccessComplete, + Subtask, + &Subtask->DiskIo2Token.Event + ); + if (!EFI_ERROR (Status)) { + InsertTailList (&Task->Subtasks, &Subtask->Link); + } else { + FreePool (Subtask); + } + } + } + } + } + + if (EFI_ERROR (Status)) { + Volume->DiskError = TRUE; + DEBUG ((EFI_D_ERROR, "FatDiskIo: error %r\n", Status)); + } + + return Status; +} + +VOID +FatAcquireLock ( + VOID + ) +/*++ + +Routine Description: + + Lock the volume. + +Arguments: + + None. + +Returns: + + None. + +--*/ +{ + EfiAcquireLock (&FatFsLock); +} + +EFI_STATUS +FatAcquireLockOrFail ( + VOID + ) +/*++ + +Routine Description: + + Lock the volume. + If the lock is already in the acquired state, then EFI_ACCESS_DENIED is returned. + Otherwise, EFI_SUCCESS is returned. + +Arguments: + + None. + +Returns: + + EFI_SUCCESS - The volume is locked. + EFI_ACCESS_DENIED - The volume could not be locked because it is already locked. + +--*/ +{ + return EfiAcquireLockOrFail (&FatFsLock); +} + +VOID +FatReleaseLock ( + VOID + ) +/*++ + +Routine Description: + + Unlock the volume. + +Arguments: + + Null. + +Returns: + + None. + +--*/ +{ + EfiReleaseLock (&FatFsLock); +} + +VOID +FatFreeDirEnt ( + IN FAT_DIRENT *DirEnt + ) +/*++ + +Routine Description: + + Free directory entry. + +Arguments: + + DirEnt - The directory entry to be freed. + +Returns: + + None. + +--*/ +{ + if (DirEnt->FileString != NULL) { + FreePool (DirEnt->FileString); + } + + FreePool (DirEnt); +} + +VOID +FatFreeVolume ( + IN FAT_VOLUME *Volume + ) +/*++ + +Routine Description: + + Free volume structure (including the contents of directory cache and disk cache). + +Arguments: + + Volume - The volume structure to be freed. + +Returns: + + None. + +--*/ +{ + // + // Free disk cache + // + if (Volume->CacheBuffer != NULL) { + FreePool (Volume->CacheBuffer); + } + // + // Free directory cache + // + FatCleanupODirCache (Volume); + FreePool (Volume); +} + +VOID +FatEfiTimeToFatTime ( + IN EFI_TIME *ETime, + OUT FAT_DATE_TIME *FTime + ) +/*++ + +Routine Description: + + Translate EFI time to FAT time. + +Arguments: + + ETime - The time of EFI_TIME. + FTime - The time of FAT_DATE_TIME. + +Returns: + + None. + +--*/ +{ + // + // ignores timezone info in source ETime + // + if (ETime->Year > 1980) { + FTime->Date.Year = (UINT16) (ETime->Year - 1980); + } + + if (ETime->Year >= 1980 + FAT_MAX_YEAR_FROM_1980) { + FTime->Date.Year = FAT_MAX_YEAR_FROM_1980; + } + + FTime->Date.Month = ETime->Month; + FTime->Date.Day = ETime->Day; + FTime->Time.Hour = ETime->Hour; + FTime->Time.Minute = ETime->Minute; + FTime->Time.DoubleSecond = (UINT16) (ETime->Second / 2); +} + +VOID +FatFatTimeToEfiTime ( + IN FAT_DATE_TIME *FTime, + OUT EFI_TIME *ETime + ) +/*++ + +Routine Description: + + Translate Fat time to EFI time. + +Arguments: + + FTime - The time of FAT_DATE_TIME. + ETime - The time of EFI_TIME. + +Returns: + + None. + +--*/ +{ + ETime->Year = (UINT16) (FTime->Date.Year + 1980); + ETime->Month = (UINT8) FTime->Date.Month; + ETime->Day = (UINT8) FTime->Date.Day; + ETime->Hour = (UINT8) FTime->Time.Hour; + ETime->Minute = (UINT8) FTime->Time.Minute; + ETime->Second = (UINT8) (FTime->Time.DoubleSecond * 2); + ETime->Nanosecond = 0; + ETime->TimeZone = EFI_UNSPECIFIED_TIMEZONE; + ETime->Daylight = 0; +} + +VOID +FatGetCurrentFatTime ( + OUT FAT_DATE_TIME *FatNow + ) +/*++ + +Routine Description: + + Get Current FAT time. + +Arguments: + + FatNow - Current FAT time. + +Returns: + + None. + +--*/ +{ + EFI_STATUS Status; + EFI_TIME Now; + + Status = gRT->GetTime (&Now, NULL); + if (!EFI_ERROR (Status)) { + FatEfiTimeToFatTime (&Now, FatNow); + } else { + ZeroMem (&Now, sizeof (EFI_TIME)); + Now.Year = 1980; + Now.Month = 1; + Now.Day = 1; + FatEfiTimeToFatTime (&Now, FatNow); + } +} + +BOOLEAN +FatIsValidTime ( + IN EFI_TIME *Time + ) +/*++ + +Routine Description: + + Check whether a time is valid. + +Arguments: + + Time - The time of EFI_TIME. + +Returns: + + TRUE - The time is valid. + FALSE - The time is not valid. + +--*/ +{ + static UINT8 MonthDays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + UINTN Day; + BOOLEAN ValidTime; + + ValidTime = TRUE; + + // + // Check the fields for range problems + // Fat can only support from 1980 + // + if (Time->Year < 1980 || + Time->Month < 1 || + Time->Month > 12 || + Time->Day < 1 || + Time->Day > 31 || + Time->Hour > 23 || + Time->Minute > 59 || + Time->Second > 59 || + Time->Nanosecond > 999999999 + ) { + + ValidTime = FALSE; + + } else { + // + // Perform a more specific check of the day of the month + // + Day = MonthDays[Time->Month - 1]; + if (Time->Month == 2 && IS_LEAP_YEAR (Time->Year)) { + Day += 1; + // + // 1 extra day this month + // + } + if (Time->Day > Day) { + ValidTime = FALSE; + } + } + + return ValidTime; +} diff --git a/FatPkg/EnhancedFatDxe/Open.c b/FatPkg/EnhancedFatDxe/Open.c new file mode 100644 index 0000000..b92e08a --- /dev/null +++ b/FatPkg/EnhancedFatDxe/Open.c @@ -0,0 +1,352 @@ +/*++ + +Copyright (c) 2005 - 2014, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the Software +License Agreement which accompanies this distribution. + + +Module Name: + + open.c + +Abstract: + + Routines dealing with file open + +Revision History + +--*/ + +#include "Fat.h" + +EFI_STATUS +FatAllocateIFile ( + IN FAT_OFILE *OFile, + OUT FAT_IFILE **PtrIFile + ) +/*++ + +Routine Description: + + Create an Open instance for the existing OFile. + The IFile of the newly opened file is passed out. + +Arguments: + + OFile - The file that serves as a starting reference point. + PtrIFile - The newly generated IFile instance. + +Returns: + + EFI_OUT_OF_RESOURCES - Can not allocate the memory for the IFile + EFI_SUCCESS - Create the new IFile for the OFile successfully + +--*/ +{ + FAT_IFILE *IFile; + + ASSERT_VOLUME_LOCKED (OFile->Volume); + + // + // Allocate a new open instance + // + IFile = AllocateZeroPool (sizeof (FAT_IFILE)); + if (IFile == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + IFile->Signature = FAT_IFILE_SIGNATURE; + + CopyMem (&(IFile->Handle), &FatFileInterface, sizeof (EFI_FILE_PROTOCOL)); + + // + // Report the correct revision number based on the DiskIo2 availability + // + if (OFile->Volume->DiskIo2 != NULL) { + IFile->Handle.Revision = EFI_FILE_PROTOCOL_REVISION2; + } else { + IFile->Handle.Revision = EFI_FILE_PROTOCOL_REVISION; + } + + IFile->OFile = OFile; + InsertTailList (&OFile->Opens, &IFile->Link); + InitializeListHead (&IFile->Tasks); + + *PtrIFile = IFile; + return EFI_SUCCESS; +} + +EFI_STATUS +FatOFileOpen ( + IN FAT_OFILE *OFile, + OUT FAT_IFILE **NewIFile, + IN CHAR16 *FileName, + IN UINT64 OpenMode, + IN UINT8 Attributes + ) +/*++ + +Routine Description: + + Open a file for a file name relative to an existing OFile. + The IFile of the newly opened file is passed out. + +Arguments: + + OFile - The file that serves as a starting reference point. + NewIFile - The newly generated IFile instance. + FileName - The file name relative to the OFile. + OpenMode - Open mode. + Attributes - Attributes to set if the file is created. + +Returns: + + EFI_SUCCESS - Open the file successfully. + EFI_INVALID_PARAMETER - The open mode is conflict with the attributes + or the file name is not valid. + EFI_NOT_FOUND - Conficts between dir intention and attribute. + EFI_WRITE_PROTECTED - Can't open for write if the volume is read only. + EFI_ACCESS_DENIED - If the file's attribute is read only, and the + open is for read-write fail it. + EFI_OUT_OF_RESOURCES - Can not allocate the memory. + +--*/ +{ + FAT_VOLUME *Volume; + EFI_STATUS Status; + CHAR16 NewFileName[EFI_PATH_STRING_LENGTH]; + FAT_DIRENT *DirEnt; + UINT8 FileAttributes; + BOOLEAN WriteMode; + + DirEnt = NULL; + Volume = OFile->Volume; + ASSERT_VOLUME_LOCKED (Volume); + WriteMode = (BOOLEAN) (OpenMode & EFI_FILE_MODE_WRITE); + if (Volume->ReadOnly && WriteMode) { + return EFI_WRITE_PROTECTED; + } + // + // Verify the source file handle isn't in an error state + // + Status = OFile->Error; + if (EFI_ERROR (Status)) { + return Status; + } + // + // Get new OFile for the file + // + Status = FatLocateOFile (&OFile, FileName, Attributes, NewFileName); + if (EFI_ERROR (Status)) { + return Status; + } + + if (*NewFileName != 0) { + // + // If there's a remaining part of the name, then we had + // better be creating the file in the directory + // + if ((OpenMode & EFI_FILE_MODE_CREATE) == 0) { + return EFI_NOT_FOUND; + } + + Status = FatCreateDirEnt (OFile, NewFileName, Attributes, &DirEnt); + if (EFI_ERROR (Status)) { + return Status; + } + + ASSERT (DirEnt != NULL); + Status = FatOpenDirEnt (OFile, DirEnt); + if (EFI_ERROR (Status)) { + return Status; + } + + OFile = DirEnt->OFile; + if (OFile->ODir != NULL) { + // + // If we just created a directory, we need to create "." and ".." + // + Status = FatCreateDotDirEnts (OFile); + if (EFI_ERROR (Status)) { + return Status; + } + } + } + // + // If the file's attribute is read only, and the open is for + // read-write, then the access is denied. + // + FileAttributes = OFile->DirEnt->Entry.Attributes; + if ((FileAttributes & EFI_FILE_READ_ONLY) != 0 && (FileAttributes & FAT_ATTRIBUTE_DIRECTORY) == 0 && WriteMode) { + return EFI_ACCESS_DENIED; + } + // + // Create an open instance of the OFile + // + Status = FatAllocateIFile (OFile, NewIFile); + if (EFI_ERROR (Status)) { + return Status; + } + + (*NewIFile)->ReadOnly = (BOOLEAN)!WriteMode; + + DEBUG ((EFI_D_INFO, "FSOpen: Open '%S' %r\n", FileName, Status)); + return FatOFileFlush (OFile); +} + +EFI_STATUS +EFIAPI +FatOpenEx ( + IN EFI_FILE_PROTOCOL *FHand, + OUT EFI_FILE_PROTOCOL **NewHandle, + IN CHAR16 *FileName, + IN UINT64 OpenMode, + IN UINT64 Attributes, + IN OUT EFI_FILE_IO_TOKEN *Token + ) +/*++ +Routine Description: + + Implements OpenEx() of Simple File System Protocol. + +Arguments: + + FHand - File handle of the file serves as a starting reference point. + NewHandle - Handle of the file that is newly opened. + FileName - File name relative to FHand. + OpenMode - Open mode. + Attributes - Attributes to set if the file is created. + Token - A pointer to the token associated with the transaction. + +Returns: + + EFI_INVALID_PARAMETER - The FileName is NULL or the file string is empty. + The OpenMode is not supported. + The Attributes is not the valid attributes. + EFI_OUT_OF_RESOURCES - Can not allocate the memory for file string. + EFI_SUCCESS - Open the file successfully. + Others - The status of open file. + +--*/ +{ + FAT_IFILE *IFile; + FAT_IFILE *NewIFile; + FAT_OFILE *OFile; + EFI_STATUS Status; + FAT_TASK *Task; + + // + // Perform some parameter checking + // + if (FileName == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Check for a valid mode + // + switch (OpenMode) { + case EFI_FILE_MODE_READ: + case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE: + case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE: + break; + + default: + return EFI_INVALID_PARAMETER; + } + + // + // Check for valid Attributes for file creation case. + // + if (((OpenMode & EFI_FILE_MODE_CREATE) != 0) && (Attributes & (EFI_FILE_READ_ONLY | (~EFI_FILE_VALID_ATTR))) != 0) { + return EFI_INVALID_PARAMETER; + } + + IFile = IFILE_FROM_FHAND (FHand); + OFile = IFile->OFile; + Task = NULL; + + if (Token == NULL) { + FatWaitNonblockingTask (IFile); + } else { + // + // Caller shouldn't call the non-blocking interfaces if the low layer doesn't support DiskIo2. + // But if it calls, the below check can avoid crash. + // + if (FHand->Revision < EFI_FILE_PROTOCOL_REVISION2) { + return EFI_UNSUPPORTED; + } + Task = FatCreateTask (IFile, Token); + if (Task == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } + + // + // Lock + // + FatAcquireLock (); + + // + // Open the file + // + Status = FatOFileOpen (OFile, &NewIFile, FileName, OpenMode, (UINT8) Attributes); + + // + // If the file was opened, return the handle to the caller + // + if (!EFI_ERROR (Status)) { + *NewHandle = &NewIFile->Handle; + } + // + // Unlock + // + Status = FatCleanupVolume (OFile->Volume, NULL, Status, Task); + FatReleaseLock (); + + if (Token != NULL) { + if (!EFI_ERROR (Status)) { + Status = FatQueueTask (IFile, Task); + } else { + FatDestroyTask (Task); + } + } + + return Status; +} + +EFI_STATUS +EFIAPI +FatOpen ( + IN EFI_FILE_PROTOCOL *FHand, + OUT EFI_FILE_PROTOCOL **NewHandle, + IN CHAR16 *FileName, + IN UINT64 OpenMode, + IN UINT64 Attributes + ) +/*++ +Routine Description: + + Implements Open() of Simple File System Protocol. + +Arguments: + + FHand - File handle of the file serves as a starting reference point. + NewHandle - Handle of the file that is newly opened. + FileName - File name relative to FHand. + OpenMode - Open mode. + Attributes - Attributes to set if the file is created. + +Returns: + + EFI_INVALID_PARAMETER - The FileName is NULL or the file string is empty. + The OpenMode is not supported. + The Attributes is not the valid attributes. + EFI_OUT_OF_RESOURCES - Can not allocate the memory for file string. + EFI_SUCCESS - Open the file successfully. + Others - The status of open file. + +--*/ +{ + return FatOpenEx (FHand, NewHandle, FileName, OpenMode, Attributes, NULL); +} diff --git a/FatPkg/EnhancedFatDxe/OpenVolume.c b/FatPkg/EnhancedFatDxe/OpenVolume.c new file mode 100644 index 0000000..556b967 --- /dev/null +++ b/FatPkg/EnhancedFatDxe/OpenVolume.c @@ -0,0 +1,76 @@ +/*++ + +Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the Software +License Agreement which accompanies this distribution. + + +Module Name: + + OpenVolume.c + +Abstract: + + OpenVolume() function of Simple File System Protocol + +Revision History + +--*/ + +#include "Fat.h" + +EFI_STATUS +EFIAPI +FatOpenVolume ( + IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This, + OUT EFI_FILE_PROTOCOL **File + ) +/*++ + +Routine Description: + + Implements Simple File System Protocol interface function OpenVolume(). + +Arguments: + + This - Calling context. + File - the Root Directory of the volume. + +Returns: + + EFI_OUT_OF_RESOURCES - Can not allocate the memory. + EFI_VOLUME_CORRUPTED - The FAT type is error. + EFI_SUCCESS - Open the volume successfully. + +--*/ +{ + EFI_STATUS Status; + FAT_VOLUME *Volume; + FAT_IFILE *IFile; + + Volume = VOLUME_FROM_VOL_INTERFACE (This); + FatAcquireLock (); + + // + // Open Root file + // + Status = FatOpenDirEnt (NULL, &Volume->RootDirEnt); + if (EFI_ERROR (Status)) { + goto Done; + } + // + // Open a new instance to the root + // + Status = FatAllocateIFile (Volume->Root, &IFile); + if (!EFI_ERROR (Status)) { + *File = &IFile->Handle; + } + +Done: + + Status = FatCleanupVolume (Volume, Volume->Root, Status, NULL); + FatReleaseLock (); + + return Status; +} diff --git a/FatPkg/EnhancedFatDxe/ReadWrite.c b/FatPkg/EnhancedFatDxe/ReadWrite.c new file mode 100644 index 0000000..21cb9e5 --- /dev/null +++ b/FatPkg/EnhancedFatDxe/ReadWrite.c @@ -0,0 +1,700 @@ +/*++ + +Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the Software +License Agreement which accompanies this distribution. + + +Module Name: + + ReadWrite.c + +Abstract: + + Functions that perform file read/write + +Revision History + +--*/ + +#include "Fat.h" + +EFI_STATUS +EFIAPI +FatGetPosition ( + IN EFI_FILE_PROTOCOL *FHand, + OUT UINT64 *Position + ) +/*++ + +Routine Description: + + Get the file's position of the file. + +Arguments: + + FHand - The handle of file. + Position - The file's position of the file. + +Returns: + + EFI_SUCCESS - Get the info successfully. + EFI_DEVICE_ERROR - Can not find the OFile for the file. + EFI_UNSUPPORTED - The open file is not a file. + +--*/ +{ + FAT_IFILE *IFile; + FAT_OFILE *OFile; + + IFile = IFILE_FROM_FHAND (FHand); + OFile = IFile->OFile; + + if (OFile->Error == EFI_NOT_FOUND) { + return EFI_DEVICE_ERROR; + } + + if (OFile->ODir != NULL) { + return EFI_UNSUPPORTED; + } + + *Position = IFile->Position; + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +FatSetPosition ( + IN EFI_FILE_PROTOCOL *FHand, + IN UINT64 Position + ) +/*++ + +Routine Description: + + Set the file's position of the file. + +Arguments: + + FHand - The handle of file. + Position - The file's position of the file. + +Returns: + + EFI_SUCCESS - Set the info successfully. + EFI_DEVICE_ERROR - Can not find the OFile for the file. + EFI_UNSUPPORTED - Set a directory with a not-zero position. + +--*/ +{ + FAT_IFILE *IFile; + FAT_OFILE *OFile; + + IFile = IFILE_FROM_FHAND (FHand); + OFile = IFile->OFile; + + if (OFile->Error == EFI_NOT_FOUND) { + return EFI_DEVICE_ERROR; + } + + FatWaitNonblockingTask (IFile); + + // + // If this is a directory, we can only set back to position 0 + // + if (OFile->ODir != NULL) { + if (Position != 0) { + // + // Reset current directory cursor; + // + return EFI_UNSUPPORTED; + } + + FatResetODirCursor (OFile); + } + // + // Set the position + // + if (Position == (UINT64)-1) { + Position = OFile->FileSize; + } + // + // Set the position + // + IFile->Position = Position; + return EFI_SUCCESS; +} + +EFI_STATUS +FatIFileReadDir ( + IN FAT_IFILE *IFile, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Get the file info from the open file of the IFile into Buffer. + +Arguments: + + IFile - The instance of the open file. + BufferSize - Size of Buffer. + Buffer - Buffer containing read data. + +Returns: + + EFI_SUCCESS - Get the file info successfully. + other - An error occurred when operation the disk. + +--*/ +{ + EFI_STATUS Status; + FAT_OFILE *OFile; + FAT_ODIR *ODir; + FAT_DIRENT *DirEnt; + UINT32 CurrentPos; + + OFile = IFile->OFile; + ODir = OFile->ODir; + CurrentPos = ((UINT32) IFile->Position) / sizeof (FAT_DIRECTORY_ENTRY); + + // + // We need to relocate the directory + // + if (CurrentPos < ODir->CurrentPos) { + // + // The directory cursor has been modified by another IFile, we reset the cursor + // + FatResetODirCursor (OFile); + } + // + // We seek the next directory entry's position + // + do { + Status = FatGetNextDirEnt (OFile, &DirEnt); + if (EFI_ERROR (Status) || DirEnt == NULL) { + // + // Something error occurred or reach the end of directory, + // return 0 buffersize + // + *BufferSize = 0; + goto Done; + } + } while (ODir->CurrentPos <= CurrentPos); + Status = FatGetDirEntInfo (OFile->Volume, DirEnt, BufferSize, Buffer); + +Done: + // + // Update IFile's Position + // + if (!EFI_ERROR (Status)) { + // + // Update IFile->Position, if everything is all right + // + CurrentPos = ODir->CurrentPos; + IFile->Position = (UINT64) (CurrentPos * sizeof (FAT_DIRECTORY_ENTRY)); + } + + return Status; +} + +EFI_STATUS +FatIFileAccess ( + IN EFI_FILE_PROTOCOL *FHand, + IN IO_MODE IoMode, + IN OUT UINTN *BufferSize, + IN OUT VOID *Buffer, + IN EFI_FILE_IO_TOKEN *Token + ) +/*++ + +Routine Description: + + Get the file info from the open file of the IFile into Buffer. + +Arguments: + + FHand - The file handle to access. + IoMode - Indicate whether the access mode is reading or writing. + BufferSize - Size of Buffer. + Buffer - Buffer containing read data. + Token - A pointer to the token associated with the transaction. + +Returns: + + EFI_SUCCESS - Get the file info successfully. + EFI_DEVICE_ERROR - Can not find the OFile for the file. + EFI_VOLUME_CORRUPTED - The file type of open file is error. + EFI_WRITE_PROTECTED - The disk is write protect. + EFI_ACCESS_DENIED - The file is read-only. + other - An error occurred when operating on the disk. + +--*/ +{ + EFI_STATUS Status; + FAT_IFILE *IFile; + FAT_OFILE *OFile; + FAT_VOLUME *Volume; + UINT64 EndPosition; + FAT_TASK *Task; + + IFile = IFILE_FROM_FHAND (FHand); + OFile = IFile->OFile; + Volume = OFile->Volume; + Task = NULL; + + // + // Write to a directory is unsupported + // + if ((OFile->ODir != NULL) && (IoMode == WRITE_DATA)) { + return EFI_UNSUPPORTED; + } + + if (OFile->Error == EFI_NOT_FOUND) { + return EFI_DEVICE_ERROR; + } + + if (IoMode == READ_DATA) { + // + // If position is at EOF, then return device error + // + if (IFile->Position > OFile->FileSize) { + return EFI_DEVICE_ERROR; + } + } else { + // + // Check if the we can write data + // + if (Volume->ReadOnly) { + return EFI_WRITE_PROTECTED; + } + + if (IFile->ReadOnly) { + return EFI_ACCESS_DENIED; + } + } + + if (Token == NULL) { + FatWaitNonblockingTask (IFile); + } else { + // + // Caller shouldn't call the non-blocking interfaces if the low layer doesn't support DiskIo2. + // But if it calls, the below check can avoid crash. + // + if (FHand->Revision < EFI_FILE_PROTOCOL_REVISION2) { + return EFI_UNSUPPORTED; + } + Task = FatCreateTask (IFile, Token); + if (Task == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } + + FatAcquireLock (); + + Status = OFile->Error; + if (!EFI_ERROR (Status)) { + if (OFile->ODir != NULL) { + // + // Read a directory is supported + // + ASSERT (IoMode == READ_DATA); + Status = FatIFileReadDir (IFile, BufferSize, Buffer); + OFile = NULL; + } else { + // + // Access a file + // + EndPosition = IFile->Position + *BufferSize; + if (EndPosition > OFile->FileSize) { + // + // The position goes beyond the end of file + // + if (IoMode == READ_DATA) { + // + // Adjust the actual size read + // + *BufferSize -= (UINTN) EndPosition - OFile->FileSize; + } else { + // + // We expand the file size of OFile + // + Status = FatGrowEof (OFile, EndPosition); + if (EFI_ERROR (Status)) { + // + // Must update the file's info into the file's Directory Entry + // and then flush the dirty cache info into disk. + // + *BufferSize = 0; + FatOFileFlush (OFile); + OFile = NULL; + goto Done; + } + + FatUpdateDirEntClusterSizeInfo (OFile); + } + } + + Status = FatAccessOFile (OFile, IoMode, (UINTN) IFile->Position, BufferSize, Buffer, Task); + IFile->Position += *BufferSize; + } + } + + if (Token != NULL) { + if (!EFI_ERROR (Status)) { + Status = FatQueueTask (IFile, Task); + } else { + FatDestroyTask (Task); + } + } + +Done: + // + // On EFI_SUCCESS case, not calling FatCleanupVolume(): + // 1) The Cache flush operation is avoided to enhance + // performance. Caller is responsible to call Flush() when necessary. + // 2) The volume dirty bit is probably set already, and is expected to be + // cleaned in subsequent Flush() or other operations. + // 3) Write operation doesn't affect OFile/IFile structure, so + // Reference checking is not necessary. + // + if (EFI_ERROR (Status)) { + Status = FatCleanupVolume (Volume, OFile, Status, NULL); + } + + FatReleaseLock (); + return Status; +} + +EFI_STATUS +EFIAPI +FatRead ( + IN EFI_FILE_PROTOCOL *FHand, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Get the file info. + +Arguments: + + FHand - The handle of the file. + BufferSize - Size of Buffer. + Buffer - Buffer containing read data. + +Returns: + + EFI_SUCCESS - Get the file info successfully. + EFI_DEVICE_ERROR - Can not find the OFile for the file. + EFI_VOLUME_CORRUPTED - The file type of open file is error. + other - An error occurred when operation the disk. + +--*/ +{ + return FatIFileAccess (FHand, READ_DATA, BufferSize, Buffer, NULL); +} + +EFI_STATUS +EFIAPI +FatReadEx ( + IN EFI_FILE_PROTOCOL *FHand, + IN OUT EFI_FILE_IO_TOKEN *Token + ) +/*++ + +Routine Description: + + Get the file info. + +Arguments: + + FHand - The handle of the file. + Token - A pointer to the token associated with the transaction. + +Returns: + + EFI_SUCCESS - Get the file info successfully. + EFI_DEVICE_ERROR - Can not find the OFile for the file. + EFI_VOLUME_CORRUPTED - The file type of open file is error. + other - An error occurred when operation the disk. + +--*/ +{ + return FatIFileAccess (FHand, READ_DATA, &Token->BufferSize, Token->Buffer, Token); +} + +EFI_STATUS +EFIAPI +FatWrite ( + IN EFI_FILE_PROTOCOL *FHand, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Write the content of buffer into files. + +Arguments: + + FHand - The handle of the file. + BufferSize - Size of Buffer. + Buffer - Buffer containing write data. + +Returns: + + EFI_SUCCESS - Set the file info successfully. + EFI_WRITE_PROTECTED - The disk is write protect. + EFI_ACCESS_DENIED - The file is read-only. + EFI_DEVICE_ERROR - The OFile is not valid. + EFI_UNSUPPORTED - The open file is not a file. + - The writing file size is larger than 4GB. + other - An error occurred when operation the disk. + +--*/ +{ + return FatIFileAccess (FHand, WRITE_DATA, BufferSize, Buffer, NULL); +} + +EFI_STATUS +EFIAPI +FatWriteEx ( + IN EFI_FILE_PROTOCOL *FHand, + IN OUT EFI_FILE_IO_TOKEN *Token + ) +/*++ + +Routine Description: + + Get the file info. + +Arguments: + + FHand - The handle of the file. + Token - A pointer to the token associated with the transaction. + +Returns: + + EFI_SUCCESS - Get the file info successfully. + EFI_DEVICE_ERROR - Can not find the OFile for the file. + EFI_VOLUME_CORRUPTED - The file type of open file is error. + other - An error occurred when operation the disk. + +--*/ +{ + return FatIFileAccess (FHand, WRITE_DATA, &Token->BufferSize, Token->Buffer, Token); +} + +EFI_STATUS +FatAccessOFile ( + IN FAT_OFILE *OFile, + IN IO_MODE IoMode, + IN UINTN Position, + IN OUT UINTN *DataBufferSize, + IN OUT UINT8 *UserBuffer, + IN FAT_TASK *Task + ) +/*++ + +Routine Description: + + This function reads data from a file or writes data to a file. + It uses OFile->PosRem to determine how much data can be accessed in one time. + +Arguments: + + OFile - The open file. + IoMode - Indicate whether the access mode is reading or writing. + Position - The position where data will be accessed. + DataBufferSize - Size of Buffer. + UserBuffer - Buffer containing data. + +Returns: + + EFI_SUCCESS - Access the data successfully. + other - An error occurred when operating on the disk. + +--*/ +{ + FAT_VOLUME *Volume; + UINTN Len; + EFI_STATUS Status; + UINTN BufferSize; + + BufferSize = *DataBufferSize; + Volume = OFile->Volume; + ASSERT_VOLUME_LOCKED (Volume); + + Status = EFI_SUCCESS; + while (BufferSize > 0) { + // + // Seek the OFile to the file position + // + Status = FatOFilePosition (OFile, Position, BufferSize); + if (EFI_ERROR (Status)) { + break; + } + // + // Clip length to block run + // + Len = BufferSize > OFile->PosRem ? OFile->PosRem : BufferSize; + + // + // Write the data + // + Status = FatDiskIo (Volume, IoMode, OFile->PosDisk, Len, UserBuffer, Task); + if (EFI_ERROR (Status)) { + break; + } + // + // Data was successfully accessed + // + Position += Len; + UserBuffer += Len; + BufferSize -= Len; + if (IoMode == WRITE_DATA) { + OFile->Dirty = TRUE; + OFile->Archive = TRUE; + } + // + // Make sure no outbound occurred + // + ASSERT (Position <= OFile->FileSize); + } + // + // Update the number of bytes accessed + // + *DataBufferSize -= BufferSize; + return Status; +} + +EFI_STATUS +FatExpandOFile ( + IN FAT_OFILE *OFile, + IN UINT64 ExpandedSize + ) +/*++ + +Routine Description: + + Expand OFile by appending zero bytes at the end of OFile. + +Arguments: + + OFile - The open file. + ExpandedSize - The number of zero bytes appended at the end of the file. + +Returns: + + EFI_SUCCESS - The file is expanded successfully. + other - An error occurred when expanding file. + +--*/ +{ + EFI_STATUS Status; + UINTN WritePos; + + WritePos = OFile->FileSize; + Status = FatGrowEof (OFile, ExpandedSize); + if (!EFI_ERROR (Status)) { + Status = FatWriteZeroPool (OFile, WritePos); + } + + return Status; +} + +EFI_STATUS +FatWriteZeroPool ( + IN FAT_OFILE *OFile, + IN UINTN WritePos + ) +/*++ + +Routine Description: + + Write zero pool from the WritePos to the end of OFile. + +Arguments: + + OFile - The open file to write zero pool. + WritePos - The number of zero bytes written. + +Returns: + + EFI_SUCCESS - Write the zero pool successfully. + EFI_OUT_OF_RESOURCES - Not enough memory to perform the operation. + other - An error occurred when writing disk. + +--*/ +{ + EFI_STATUS Status; + VOID *ZeroBuffer; + UINTN AppendedSize; + UINTN BufferSize; + UINTN WriteSize; + + AppendedSize = OFile->FileSize - WritePos; + BufferSize = AppendedSize; + if (AppendedSize > FAT_MAX_ALLOCATE_SIZE) { + // + // If the appended size is larger, maybe we can not allocate the whole + // memory once. So if the growed size is larger than 10M, we just + // allocate 10M memory (one healthy system should have 10M available + // memory), and then write the zerobuffer to the file several times. + // + BufferSize = FAT_MAX_ALLOCATE_SIZE; + } + + ZeroBuffer = AllocateZeroPool (BufferSize); + if (ZeroBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + do { + WriteSize = AppendedSize > BufferSize ? BufferSize : (UINTN) AppendedSize; + AppendedSize -= WriteSize; + Status = FatAccessOFile (OFile, WRITE_DATA, WritePos, &WriteSize, ZeroBuffer, NULL); + if (EFI_ERROR (Status)) { + break; + } + + WritePos += WriteSize; + } while (AppendedSize > 0); + + FreePool (ZeroBuffer); + return Status; +} + +EFI_STATUS +FatTruncateOFile ( + IN FAT_OFILE *OFile, + IN UINTN TruncatedSize + ) +/*++ + +Routine Description: + + Truncate the OFile to smaller file size. + +Arguments: + + OFile - The open file. + TruncatedSize - The new file size. + +Returns: + + EFI_SUCCESS - The file is truncated successfully. + other - An error occurred when truncating file. + +--*/ +{ + OFile->FileSize = TruncatedSize; + return FatShrinkEof (OFile); +} diff --git a/FatPkg/EnhancedFatDxe/UnicodeCollation.c b/FatPkg/EnhancedFatDxe/UnicodeCollation.c new file mode 100644 index 0000000..c6c7aea --- /dev/null +++ b/FatPkg/EnhancedFatDxe/UnicodeCollation.c @@ -0,0 +1,279 @@ +/** @file + Unicode Collation Support component that hides the trivial difference of Unicode Collation + and Unicode collation 2 Protocol. + + Copyright (c) 2007 - 2013, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the Software + License Agreement which accompanies this distribution. + +**/ + +#include "Fat.h" + +EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollationInterface = NULL; + +/** + Worker function to initialize Unicode Collation support. + + It tries to locate Unicode Collation (2) protocol and matches it with current + platform language code. + + @param AgentHandle The handle used to open Unicode Collation (2) protocol. + @param ProtocolGuid The pointer to Unicode Collation (2) protocol GUID. + @param VariableName The name of the RFC 4646 or ISO 639-2 language variable. + @param DefaultLanguage The default language in case the RFC 4646 or ISO 639-2 language is absent. + + @retval EFI_SUCCESS The Unicode Collation (2) protocol has been successfully located. + @retval Others The Unicode Collation (2) protocol has not been located. + +**/ +EFI_STATUS +InitializeUnicodeCollationSupportWorker ( + IN EFI_HANDLE AgentHandle, + IN EFI_GUID *ProtocolGuid, + IN CONST CHAR16 *VariableName, + IN CONST CHAR8 *DefaultLanguage + ) +{ + EFI_STATUS ReturnStatus; + EFI_STATUS Status; + UINTN NumHandles; + UINTN Index; + EFI_HANDLE *Handles; + EFI_UNICODE_COLLATION_PROTOCOL *Uci; + BOOLEAN Iso639Language; + CHAR8 *Language; + CHAR8 *BestLanguage; + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + ProtocolGuid, + NULL, + &NumHandles, + &Handles + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Iso639Language = (BOOLEAN) (ProtocolGuid == &gEfiUnicodeCollationProtocolGuid); + GetEfiGlobalVariable2 (VariableName, (VOID**) &Language, NULL); + + ReturnStatus = EFI_UNSUPPORTED; + for (Index = 0; Index < NumHandles; Index++) { + // + // Open Unicode Collation Protocol + // + Status = gBS->OpenProtocol ( + Handles[Index], + ProtocolGuid, + (VOID **) &Uci, + AgentHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + continue; + } + + // + // Find the best matching matching language from the supported languages + // of Unicode Collation (2) protocol. + // + BestLanguage = GetBestLanguage ( + Uci->SupportedLanguages, + Iso639Language, + (Language == NULL) ? "" : Language, + DefaultLanguage, + NULL + ); + if (BestLanguage != NULL) { + FreePool (BestLanguage); + mUnicodeCollationInterface = Uci; + ReturnStatus = EFI_SUCCESS; + break; + } + } + + if (Language != NULL) { + FreePool (Language); + } + + FreePool (Handles); + + return ReturnStatus; +} + +/** + Initialize Unicode Collation support. + + It tries to locate Unicode Collation 2 protocol and matches it with current + platform language code. If for any reason the first attempt fails, it then tries to + use Unicode Collation Protocol. + + @param AgentHandle The handle used to open Unicode Collation (2) protocol. + + @retval EFI_SUCCESS The Unicode Collation (2) protocol has been successfully located. + @retval Others The Unicode Collation (2) protocol has not been located. + +**/ +EFI_STATUS +InitializeUnicodeCollationSupport ( + IN EFI_HANDLE AgentHandle + ) +{ + + EFI_STATUS Status; + + Status = EFI_UNSUPPORTED; + + // + // First try to use RFC 4646 Unicode Collation 2 Protocol. + // + Status = InitializeUnicodeCollationSupportWorker ( + AgentHandle, + &gEfiUnicodeCollation2ProtocolGuid, + L"PlatformLang", + (CONST CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLang) + ); + // + // If the attempt to use Unicode Collation 2 Protocol fails, then we fall back + // on the ISO 639-2 Unicode Collation Protocol. + // + if (EFI_ERROR (Status)) { + Status = InitializeUnicodeCollationSupportWorker ( + AgentHandle, + &gEfiUnicodeCollationProtocolGuid, + L"Lang", + (CONST CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultLang) + ); + } + + return Status; +} + + +/** + Performs a case-insensitive comparison of two Null-terminated Unicode strings. + + @param S1 A pointer to a Null-terminated Unicode string. + @param S2 A pointer to a Null-terminated Unicode string. + + @retval 0 S1 is equivalent to S2. + @retval >0 S1 is lexically greater than S2. + @retval <0 S1 is lexically less than S2. +**/ +INTN +FatStriCmp ( + IN CHAR16 *S1, + IN CHAR16 *S2 + ) +{ + ASSERT (StrSize (S1) != 0); + ASSERT (StrSize (S2) != 0); + ASSERT (mUnicodeCollationInterface != NULL); + + return mUnicodeCollationInterface->StriColl ( + mUnicodeCollationInterface, + S1, + S2 + ); +} + + +/** + Uppercase a string. + + @param Str The string which will be upper-cased. + + @return None. + +**/ +VOID +FatStrUpr ( + IN OUT CHAR16 *String + ) +{ + ASSERT (StrSize (String) != 0); + ASSERT (mUnicodeCollationInterface != NULL); + + mUnicodeCollationInterface->StrUpr (mUnicodeCollationInterface, String); +} + + +/** + Lowercase a string + + @param Str The string which will be lower-cased. + + @return None + +**/ +VOID +FatStrLwr ( + IN OUT CHAR16 *String + ) +{ + ASSERT (StrSize (String) != 0); + ASSERT (mUnicodeCollationInterface != NULL); + + mUnicodeCollationInterface->StrLwr (mUnicodeCollationInterface, String); +} + + +/** + Convert FAT string to unicode string. + + @param FatSize The size of FAT string. + @param Fat The FAT string. + @param String The unicode string. + + @return None. + +**/ +VOID +FatFatToStr ( + IN UINTN FatSize, + IN CHAR8 *Fat, + OUT CHAR16 *String + ) +{ + ASSERT (Fat != NULL); + ASSERT (String != NULL); + ASSERT (((UINTN) String & 0x01) == 0); + ASSERT (mUnicodeCollationInterface != NULL); + + mUnicodeCollationInterface->FatToStr (mUnicodeCollationInterface, FatSize, Fat, String); +} + + +/** + Convert unicode string to Fat string. + + @param String The unicode string. + @param FatSize The size of the FAT string. + @param Fat The FAT string. + + @retval TRUE Convert successfully. + @retval FALSE Convert error. + +**/ +BOOLEAN +FatStrToFat ( + IN CHAR16 *String, + IN UINTN FatSize, + OUT CHAR8 *Fat + ) +{ + ASSERT (Fat != NULL); + ASSERT (StrSize (String) != 0); + ASSERT (mUnicodeCollationInterface != NULL); + + return mUnicodeCollationInterface->StrToFat ( + mUnicodeCollationInterface, + String, + FatSize, + Fat + ); +} diff --git a/FatPkg/FatPei/FatLiteAccess.c b/FatPkg/FatPei/FatLiteAccess.c new file mode 100644 index 0000000..a409eac --- /dev/null +++ b/FatPkg/FatPei/FatLiteAccess.c @@ -0,0 +1,523 @@ +/** @file + FAT file system access routines for FAT recovery PEIM + +Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.
+ +This program and the accompanying materials +are licensed and made available under the terms and conditions of the Software +License Agreement which accompanies this distribution. + +**/ + +#include "FatLitePeim.h" + + +/** + Check if there is a valid FAT in the corresponding Block device + of the volume and if yes, fill in the relevant fields for the + volume structure. Note there should be a valid Block device number + already set. + + @param PrivateData Global memory map for accessing global + variables. + @param Volume On input, the BlockDeviceNumber field of the + Volume should be a valid value. On successful + output, all fields except the VolumeNumber + field is initialized. + + @retval EFI_SUCCESS A FAT is found and the volume structure is + initialized. + @retval EFI_NOT_FOUND There is no FAT on the corresponding device. + @retval EFI_DEVICE_ERROR There is something error while accessing device. + +**/ +EFI_STATUS +FatGetBpbInfo ( + IN PEI_FAT_PRIVATE_DATA *PrivateData, + IN OUT PEI_FAT_VOLUME *Volume + ) +{ + EFI_STATUS Status; + PEI_FAT_BOOT_SECTOR Bpb; + PEI_FAT_BOOT_SECTOR_EX BpbEx; + UINT32 Sectors; + UINT32 SectorsPerFat; + UINT32 RootDirSectors; + UINT64 FatLba; + UINT64 RootLba; + UINT64 FirstClusterLba; + + // + // Read in the BPB + // + Status = FatReadDisk ( + PrivateData, + Volume->BlockDeviceNo, + 0, + sizeof (PEI_FAT_BOOT_SECTOR_EX), + &BpbEx + ); + if (EFI_ERROR (Status)) { + return Status; + } + + CopyMem ( + (UINT8 *) (&Bpb), + (UINT8 *) (&BpbEx), + sizeof (PEI_FAT_BOOT_SECTOR) + ); + + Volume->FatType = FatUnknown; + + Sectors = Bpb.Sectors; + if (Sectors == 0) { + Sectors = Bpb.LargeSectors; + } + + SectorsPerFat = Bpb.SectorsPerFat; + if (SectorsPerFat == 0) { + SectorsPerFat = BpbEx.LargeSectorsPerFat; + Volume->FatType = Fat32; + } + // + // Filter out those not a FAT + // + if (Bpb.Ia32Jump[0] != 0xe9 && Bpb.Ia32Jump[0] != 0xeb && Bpb.Ia32Jump[0] != 0x49) { + return EFI_NOT_FOUND; + } + + if (Bpb.ReservedSectors == 0 || Bpb.NoFats == 0 || Sectors == 0) { + return EFI_NOT_FOUND; + } + + if (Bpb.SectorsPerCluster != 1 && + Bpb.SectorsPerCluster != 2 && + Bpb.SectorsPerCluster != 4 && + Bpb.SectorsPerCluster != 8 && + Bpb.SectorsPerCluster != 16 && + Bpb.SectorsPerCluster != 32 && + Bpb.SectorsPerCluster != 64 && + Bpb.SectorsPerCluster != 128 + ) { + return EFI_NOT_FOUND; + } + + if (Volume->FatType == Fat32 && (SectorsPerFat == 0 || BpbEx.FsVersion != 0)) { + return EFI_NOT_FOUND; + } + + if (Bpb.Media != 0xf0 && + Bpb.Media != 0xf8 && + Bpb.Media != 0xf9 && + Bpb.Media != 0xfb && + Bpb.Media != 0xfc && + Bpb.Media != 0xfd && + Bpb.Media != 0xfe && + Bpb.Media != 0xff && + // + // FujitsuFMR + // + Bpb.Media != 0x00 && + Bpb.Media != 0x01 && + Bpb.Media != 0xfa + ) { + return EFI_NOT_FOUND; + } + + if (Volume->FatType != Fat32 && Bpb.RootEntries == 0) { + return EFI_NOT_FOUND; + } + // + // If this is fat32, refuse to mount mirror-disabled volumes + // + if (Volume->FatType == Fat32 && ((BpbEx.ExtendedFlags & 0x80) != 0)) { + return EFI_NOT_FOUND; + } + // + // Fill in the volume structure fields + // (Sectors & SectorsPerFat is computed earlier already) + // + Volume->ClusterSize = Bpb.SectorSize * Bpb.SectorsPerCluster; + Volume->RootEntries = Bpb.RootEntries; + Volume->SectorSize = Bpb.SectorSize; + + RootDirSectors = ((Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY)) + (Volume->SectorSize - 1)) / Volume->SectorSize; + + FatLba = Bpb.ReservedSectors; + RootLba = Bpb.NoFats * SectorsPerFat + FatLba; + FirstClusterLba = RootLba + RootDirSectors; + + Volume->VolumeSize = MultU64x32 (Sectors, Volume->SectorSize); + Volume->FatPos = MultU64x32 (FatLba, Volume->SectorSize); + Volume->RootDirPos = MultU64x32 (RootLba, Volume->SectorSize); + Volume->FirstClusterPos = MultU64x32 (FirstClusterLba, Volume->SectorSize); + Volume->MaxCluster = (UINT32) (Sectors - FirstClusterLba) / Bpb.SectorsPerCluster; + Volume->RootDirCluster = BpbEx.RootDirFirstCluster; + + // + // If this is not a fat32, determine if it's a fat16 or fat12 + // + if (Volume->FatType != Fat32) { + + if (Volume->MaxCluster >= 65525) { + return EFI_NOT_FOUND; + } + + Volume->FatType = Volume->MaxCluster < 4085 ? Fat12 : Fat16; + } + + return EFI_SUCCESS; +} + + +/** + Gets the next cluster in the cluster chain + + @param PrivateData Global memory map for accessing global variables + @param Volume The volume + @param Cluster The cluster + @param NextCluster The cluster number of the next cluster + + @retval EFI_SUCCESS The address is got + @retval EFI_INVALID_PARAMETER ClusterNo exceeds the MaxCluster of the volume. + @retval EFI_DEVICE_ERROR Read disk error + +**/ +EFI_STATUS +FatGetNextCluster ( + IN PEI_FAT_PRIVATE_DATA *PrivateData, + IN PEI_FAT_VOLUME *Volume, + IN UINT32 Cluster, + OUT UINT32 *NextCluster + ) +{ + EFI_STATUS Status; + UINT64 FatEntryPos; + UINT32 Dummy; + + *NextCluster = 0; + + if (Volume->FatType == Fat32) { + FatEntryPos = Volume->FatPos + MultU64x32 (4, Cluster); + + Status = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 4, NextCluster); + *NextCluster &= 0x0fffffff; + + // + // Pad high bits for our FAT_CLUSTER_... macro definitions to work + // + if ((*NextCluster) >= 0x0ffffff7) { + *NextCluster |= (-1 &~0xf); + } + + } else if (Volume->FatType == Fat16) { + FatEntryPos = Volume->FatPos + MultU64x32 (2, Cluster); + + Status = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 2, NextCluster); + + // + // Pad high bits for our FAT_CLUSTER_... macro definitions to work + // + if ((*NextCluster) >= 0xfff7) { + *NextCluster |= (-1 &~0xf); + } + + } else { + FatEntryPos = Volume->FatPos + DivU64x32Remainder (MultU64x32 (3, Cluster), 2, &Dummy); + + Status = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 2, NextCluster); + + if ((Cluster & 0x01) != 0) { + *NextCluster = (*NextCluster) >> 4; + } else { + *NextCluster = (*NextCluster) & 0x0fff; + } + // + // Pad high bits for our FAT_CLUSTER_... macro definitions to work + // + if ((*NextCluster) >= 0x0ff7) { + *NextCluster |= (-1 &~0xf); + } + } + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; + +} + + +/** + Set a file's CurrentPos and CurrentCluster, then compute StraightReadAmount. + + @param PrivateData the global memory map + @param File the file + @param Pos the Position which is offset from the file's + CurrentPos + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Pos is beyond file's size. + @retval EFI_DEVICE_ERROR Something error while accessing media. + +**/ +EFI_STATUS +FatSetFilePos ( + IN PEI_FAT_PRIVATE_DATA *PrivateData, + IN PEI_FAT_FILE *File, + IN UINT32 Pos + ) +{ + EFI_STATUS Status; + UINT32 AlignedPos; + UINT32 Offset; + UINT32 Cluster; + UINT32 PrevCluster; + + if (File->IsFixedRootDir) { + + if (Pos >= MultU64x32 (File->Volume->RootEntries, 32) - File->CurrentPos) { + return EFI_INVALID_PARAMETER; + } + + File->CurrentPos += Pos; + File->StraightReadAmount = (UINT32) (MultU64x32 (File->Volume->RootEntries, 32) - File->CurrentPos); + + } else { + + DivU64x32Remainder (File->CurrentPos, File->Volume->ClusterSize, &Offset); + AlignedPos = (UINT32) File->CurrentPos - (UINT32) Offset; + + while + ( + !FAT_CLUSTER_FUNCTIONAL (File->CurrentCluster) && + AlignedPos + File->Volume->ClusterSize <= File->CurrentPos + Pos + ) { + AlignedPos += File->Volume->ClusterSize; + Status = FatGetNextCluster ( + PrivateData, + File->Volume, + File->CurrentCluster, + &File->CurrentCluster + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + } + + if (FAT_CLUSTER_FUNCTIONAL (File->CurrentCluster)) { + return EFI_INVALID_PARAMETER; + } + + File->CurrentPos += Pos; + // + // Calculate the amount of consecutive cluster occupied by the file. + // FatReadFile() will use it to read these blocks once. + // + File->StraightReadAmount = 0; + Cluster = File->CurrentCluster; + while (!FAT_CLUSTER_FUNCTIONAL (Cluster)) { + File->StraightReadAmount += File->Volume->ClusterSize; + PrevCluster = Cluster; + Status = FatGetNextCluster (PrivateData, File->Volume, Cluster, &Cluster); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + if (Cluster != PrevCluster + 1) { + break; + } + } + + DivU64x32Remainder (File->CurrentPos, File->Volume->ClusterSize, &Offset); + File->StraightReadAmount -= (UINT32) Offset; + + } + + return EFI_SUCCESS; +} + + +/** + Reads file data. Updates the file's CurrentPos. + + @param PrivateData Global memory map for accessing global variables + @param File The file. + @param Size The amount of data to read. + @param Buffer The buffer storing the data. + + @retval EFI_SUCCESS The data is read. + @retval EFI_INVALID_PARAMETER File is invalid. + @retval EFI_DEVICE_ERROR Something error while accessing media. + +**/ +EFI_STATUS +FatReadFile ( + IN PEI_FAT_PRIVATE_DATA *PrivateData, + IN PEI_FAT_FILE *File, + IN UINTN Size, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + CHAR8 *BufferPtr; + UINT32 Offset; + UINT64 PhysicalAddr; + UINTN Amount; + + BufferPtr = Buffer; + + if (File->IsFixedRootDir) { + // + // This is the fixed root dir in FAT12 and FAT16 + // + if (File->CurrentPos + Size > File->Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY)) { + return EFI_INVALID_PARAMETER; + } + + Status = FatReadDisk ( + PrivateData, + File->Volume->BlockDeviceNo, + File->Volume->RootDirPos + File->CurrentPos, + Size, + Buffer + ); + File->CurrentPos += (UINT32) Size; + return Status; + + } else { + + if ((File->Attributes & FAT_ATTR_DIRECTORY) == 0) { + Size = Size < (File->FileSize - File->CurrentPos) ? Size : (UINTN) (File->FileSize - File->CurrentPos); + } + // + // This is a normal cluster based file + // + while (Size != 0) { + DivU64x32Remainder (File->CurrentPos, File->Volume->ClusterSize, &Offset); + PhysicalAddr = File->Volume->FirstClusterPos + MultU64x32 (File->Volume->ClusterSize, File->CurrentCluster - 2); + + Amount = File->StraightReadAmount; + Amount = Size > Amount ? Amount : Size; + Status = FatReadDisk ( + PrivateData, + File->Volume->BlockDeviceNo, + PhysicalAddr + Offset, + Amount, + BufferPtr + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + // + // Advance the file's current pos and current cluster + // + FatSetFilePos (PrivateData, File, (UINT32) Amount); + + BufferPtr += Amount; + Size -= Amount; + } + + return EFI_SUCCESS; + } +} + + +/** + This function reads the next item in the parent directory and + initializes the output parameter SubFile (CurrentPos is initialized to 0). + The function updates the CurrentPos of the parent dir to after the item read. + If no more items were found, the function returns EFI_NOT_FOUND. + + @param PrivateData Global memory map for accessing global variables + @param ParentDir The parent directory. + @param SubFile The File structure containing the sub file that + is caught. + + @retval EFI_SUCCESS The next sub file is obtained. + @retval EFI_INVALID_PARAMETER The ParentDir is not a directory. + @retval EFI_NOT_FOUND No more sub file exists. + @retval EFI_DEVICE_ERROR Something error while accessing media. + +**/ +EFI_STATUS +FatReadNextDirectoryEntry ( + IN PEI_FAT_PRIVATE_DATA *PrivateData, + IN PEI_FAT_FILE *ParentDir, + OUT PEI_FAT_FILE *SubFile + ) +{ + EFI_STATUS Status; + FAT_DIRECTORY_ENTRY DirEntry; + CHAR16 *Pos; + CHAR16 BaseName[9]; + CHAR16 Ext[4]; + + ZeroMem ((UINT8 *) SubFile, sizeof (PEI_FAT_FILE)); + + // + // Pick a valid directory entry + // + while (1) { + // + // Read one entry + // + Status = FatReadFile (PrivateData, ParentDir, 32, &DirEntry); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + // + // We only search for *FILE* in root directory + // Long file name entry is *NOT* supported + // + if (((DirEntry.Attributes & FAT_ATTR_DIRECTORY) == FAT_ATTR_DIRECTORY) || (DirEntry.Attributes == FAT_ATTR_LFN)) { + continue; + } + // + // if this is a terminator dir entry, just return EFI_NOT_FOUND + // + if (DirEntry.FileName[0] == EMPTY_ENTRY_MARK) { + return EFI_NOT_FOUND; + } + // + // If this not an invalid entry neither an empty entry, this is what we want. + // otherwise we will start a new loop to continue to find something meaningful + // + if ((UINT8) DirEntry.FileName[0] != DELETE_ENTRY_MARK) { + break; + } + } + // + // fill in the output parameter + // + EngFatToStr (8, DirEntry.FileName, BaseName); + EngFatToStr (3, DirEntry.FileName + 8, Ext); + + Pos = (UINT16 *) SubFile->FileName; + SetMem ((UINT8 *) Pos, FAT_MAX_FILE_NAME_LENGTH, 0); + CopyMem ((UINT8 *) Pos, (UINT8 *) BaseName, 2 * (StrLen (BaseName) + 1)); + + if (Ext[0] != 0) { + Pos += StrLen (BaseName); + *Pos = '.'; + Pos++; + CopyMem ((UINT8 *) Pos, (UINT8 *) Ext, 2 * (StrLen (Ext) + 1)); + } + + SubFile->Attributes = DirEntry.Attributes; + SubFile->CurrentCluster = DirEntry.FileCluster; + if (ParentDir->Volume->FatType == Fat32) { + SubFile->CurrentCluster |= DirEntry.FileClusterHigh << 16; + } + + SubFile->CurrentPos = 0; + SubFile->FileSize = DirEntry.FileSize; + SubFile->StartingCluster = SubFile->CurrentCluster; + SubFile->Volume = ParentDir->Volume; + + // + // in Pei phase, time parameters do not need to be filled for minimum use. + // + return Status; +} diff --git a/FatPkg/FatPei/FatLiteApi.c b/FatPkg/FatPei/FatLiteApi.c new file mode 100644 index 0000000..cbc2ebd --- /dev/null +++ b/FatPkg/FatPei/FatLiteApi.c @@ -0,0 +1,618 @@ +/** @file + FAT recovery PEIM entry point, Ppi Functions and FAT Api functions. + +Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+ +This program and the accompanying materials +are licensed and made available under the terms and conditions of the Software +License Agreement which accompanies this distribution. + +**/ + +#include "FatLitePeim.h" + +PEI_FAT_PRIVATE_DATA *mPrivateData = NULL; + +/** + BlockIo installation nofication function. Find out all the current BlockIO + PPIs in the system and add them into private data. Assume there is + + @param PeiServices General purpose services available to every + PEIM. + @param NotifyDescriptor The typedef structure of the notification + descriptor. Not used in this function. + @param Ppi The typedef structure of the PPI descriptor. + Not used in this function. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +EFIAPI +BlockIoNotifyEntry ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ); + + +/** + Discover all the block I/O devices to find the FAT volume. + + @param PrivateData Global memory map for accessing global + variables. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +UpdateBlocksAndVolumes ( + IN OUT PEI_FAT_PRIVATE_DATA *PrivateData + ) +{ + EFI_STATUS Status; + EFI_PEI_PPI_DESCRIPTOR *TempPpiDescriptor; + UINTN BlockIoPpiInstance; + EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi; + UINTN NumberBlockDevices; + UINTN Index; + EFI_PEI_BLOCK_IO_MEDIA Media; + PEI_FAT_VOLUME Volume; + EFI_PEI_SERVICES **PeiServices; + + PeiServices = (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (); + + // + // Clean up caches + // + for (Index = 0; Index < PEI_FAT_CACHE_SIZE; Index++) { + PrivateData->CacheBuffer[Index].Valid = FALSE; + } + + PrivateData->BlockDeviceCount = 0; + + // + // Find out all Block Io Ppi instances within the system + // Assuming all device Block Io Peims are dispatched already + // + for (BlockIoPpiInstance = 0; BlockIoPpiInstance < PEI_FAT_MAX_BLOCK_IO_PPI; BlockIoPpiInstance++) { + Status = PeiServicesLocatePpi ( + &gEfiPeiVirtualBlockIoPpiGuid, + BlockIoPpiInstance, + &TempPpiDescriptor, + (VOID **) &BlockIoPpi + ); + if (EFI_ERROR (Status)) { + // + // Done with all Block Io Ppis + // + break; + } + + Status = BlockIoPpi->GetNumberOfBlockDevices ( + PeiServices, + BlockIoPpi, + &NumberBlockDevices + ); + if (EFI_ERROR (Status)) { + continue; + } + + for (Index = 1; Index <= NumberBlockDevices && PrivateData->BlockDeviceCount < PEI_FAT_MAX_BLOCK_DEVICE; Index++) { + + Status = BlockIoPpi->GetBlockDeviceMediaInfo ( + PeiServices, + BlockIoPpi, + Index, + &Media + ); + if (EFI_ERROR (Status) || !Media.MediaPresent) { + continue; + } + + PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockSize = (UINT32) Media.BlockSize; + PrivateData->BlockDevice[PrivateData->BlockDeviceCount].LastBlock = Media.LastBlock; + PrivateData->BlockDevice[PrivateData->BlockDeviceCount].IoAlign = 0; + // + // Not used here + // + PrivateData->BlockDevice[PrivateData->BlockDeviceCount].Logical = FALSE; + PrivateData->BlockDevice[PrivateData->BlockDeviceCount].PartitionChecked = FALSE; + + PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockIo = BlockIoPpi; + PrivateData->BlockDevice[PrivateData->BlockDeviceCount].PhysicalDevNo = (UINT8) Index; + PrivateData->BlockDevice[PrivateData->BlockDeviceCount].DevType = Media.DeviceType; + + PrivateData->BlockDeviceCount++; + } + } + // + // Find out all logical devices + // + FatFindPartitions (PrivateData); + + // + // Build up file system volume array + // + PrivateData->VolumeCount = 0; + for (Index = 0; Index < PrivateData->BlockDeviceCount; Index++) { + Volume.BlockDeviceNo = Index; + Status = FatGetBpbInfo (PrivateData, &Volume); + if (Status == EFI_SUCCESS) { + // + // Add the detected volume to the volume array + // + CopyMem ( + (UINT8 *) &(PrivateData->Volume[PrivateData->VolumeCount]), + (UINT8 *) &Volume, + sizeof (PEI_FAT_VOLUME) + ); + PrivateData->VolumeCount += 1; + if (PrivateData->VolumeCount >= PEI_FAT_MAX_VOLUME) { + break; + } + } + } + + return EFI_SUCCESS; +} + + +/** + BlockIo installation notification function. Find out all the current BlockIO + PPIs in the system and add them into private data. Assume there is + + @param PeiServices General purpose services available to every + PEIM. + @param NotifyDescriptor The typedef structure of the notification + descriptor. Not used in this function. + @param Ppi The typedef structure of the PPI descriptor. + Not used in this function. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +EFIAPI +BlockIoNotifyEntry ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ) +{ + UpdateBlocksAndVolumes (mPrivateData); + + return EFI_SUCCESS; +} + + +/** + Installs the Device Recovery Module PPI, Initialize BlockIo Ppi + installation notification + + @param FileHandle Handle of the file being invoked. Type + EFI_PEI_FILE_HANDLE is defined in + FfsFindNextFile(). + @param PeiServices Describes the list of possible PEI Services. + + @retval EFI_SUCCESS The entry point was executed successfully. + @retval EFI_OUT_OF_RESOURCES There is no enough memory to complete the + operations. + +**/ +EFI_STATUS +EFIAPI +FatPeimEntry ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS Address; + PEI_FAT_PRIVATE_DATA *PrivateData; + + Status = PeiServicesRegisterForShadow (FileHandle); + if (!EFI_ERROR (Status)) { + return Status; + } + + Status = PeiServicesAllocatePages ( + EfiBootServicesCode, + (sizeof (PEI_FAT_PRIVATE_DATA) - 1) / PEI_FAT_MEMMORY_PAGE_SIZE + 1, + &Address + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + PrivateData = (PEI_FAT_PRIVATE_DATA *) (UINTN) Address; + + // + // Initialize Private Data (to zero, as is required by subsequent operations) + // + ZeroMem ((UINT8 *) PrivateData, sizeof (PEI_FAT_PRIVATE_DATA)); + + PrivateData->Signature = PEI_FAT_PRIVATE_DATA_SIGNATURE; + + // + // Installs Ppi + // + PrivateData->DeviceRecoveryPpi.GetNumberRecoveryCapsules = GetNumberRecoveryCapsules; + PrivateData->DeviceRecoveryPpi.GetRecoveryCapsuleInfo = GetRecoveryCapsuleInfo; + PrivateData->DeviceRecoveryPpi.LoadRecoveryCapsule = LoadRecoveryCapsule; + + PrivateData->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST); + PrivateData->PpiDescriptor.Guid = &gEfiPeiDeviceRecoveryModulePpiGuid; + PrivateData->PpiDescriptor.Ppi = &PrivateData->DeviceRecoveryPpi; + + Status = PeiServicesInstallPpi (&PrivateData->PpiDescriptor); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + // + // Other initializations + // + PrivateData->BlockDeviceCount = 0; + + UpdateBlocksAndVolumes (PrivateData); + + // + // PrivateData is allocated now, set it to the module variable + // + mPrivateData = PrivateData; + + // + // Installs Block Io Ppi notification function + // + PrivateData->NotifyDescriptor.Flags = + ( + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | + EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST + ); + PrivateData->NotifyDescriptor.Guid = &gEfiPeiVirtualBlockIoPpiGuid; + PrivateData->NotifyDescriptor.Notify = BlockIoNotifyEntry; + return PeiServicesNotifyPpi (&PrivateData->NotifyDescriptor); +} + + +/** + Returns the number of DXE capsules residing on the device. + + This function searches for DXE capsules from the associated device and returns + the number and maximum size in bytes of the capsules discovered. Entry 1 is + assumed to be the highest load priority and entry N is assumed to be the lowest + priority. + + @param[in] PeiServices General-purpose services that are available + to every PEIM + @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI + instance. + @param[out] NumberRecoveryCapsules Pointer to a caller-allocated UINTN. On + output, *NumberRecoveryCapsules contains + the number of recovery capsule images + available for retrieval from this PEIM + instance. + + @retval EFI_SUCCESS One or more capsules were discovered. + @retval EFI_DEVICE_ERROR A device error occurred. + @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found. + +**/ +EFI_STATUS +EFIAPI +GetNumberRecoveryCapsules ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This, + OUT UINTN *NumberRecoveryCapsules + ) +{ + EFI_STATUS Status; + PEI_FAT_PRIVATE_DATA *PrivateData; + UINTN Index; + UINTN RecoveryCapsuleCount; + PEI_FILE_HANDLE Handle; + + PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This); + + // + // Search each volume in the root directory for the Recovery capsule + // + RecoveryCapsuleCount = 0; + for (Index = 0; Index < PrivateData->VolumeCount; Index++) { + Status = FindRecoveryFile (PrivateData, Index, PEI_FAT_RECOVERY_CAPSULE_WITHOUT_NT_EMULATOR, &Handle); + if (EFI_ERROR (Status)) { + continue; + } + + RecoveryCapsuleCount++; + } + + *NumberRecoveryCapsules = RecoveryCapsuleCount; + + if (*NumberRecoveryCapsules == 0) { + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + + +/** + Returns the size and type of the requested recovery capsule. + + This function gets the size and type of the capsule specified by CapsuleInstance. + + @param[in] PeiServices General-purpose services that are available to every PEIM + @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI + instance. + @param[in] CapsuleInstance Specifies for which capsule instance to retrieve + the information. This parameter must be between + one and the value returned by GetNumberRecoveryCapsules() + in NumberRecoveryCapsules. + @param[out] Size A pointer to a caller-allocated UINTN in which + the size of the requested recovery module is + returned. + @param[out] CapsuleType A pointer to a caller-allocated EFI_GUID in which + the type of the requested recovery capsule is + returned. The semantic meaning of the value + returned is defined by the implementation. + + @retval EFI_SUCCESS One or more capsules were discovered. + @retval EFI_DEVICE_ERROR A device error occurred. + @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found. + +**/ +EFI_STATUS +EFIAPI +GetRecoveryCapsuleInfo ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This, + IN UINTN CapsuleInstance, + OUT UINTN *Size, + OUT EFI_GUID *CapsuleType + ) +{ + EFI_STATUS Status; + PEI_FAT_PRIVATE_DATA *PrivateData; + UINTN Index; + UINTN BlockDeviceNo; + UINTN RecoveryCapsuleCount; + PEI_FILE_HANDLE Handle; + UINTN NumberRecoveryCapsules; + + Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules); + + if (EFI_ERROR (Status)) { + return Status; + } + + if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) { + CapsuleInstance = CapsuleInstance + 1; + } + + if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) { + return EFI_NOT_FOUND; + } + + PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This); + + // + // Search each volume in the root directory for the Recovery capsule + // + RecoveryCapsuleCount = 0; + for (Index = 0; Index < PrivateData->VolumeCount; Index++) { + Status = FindRecoveryFile (PrivateData, Index, PEI_FAT_RECOVERY_CAPSULE_WITHOUT_NT_EMULATOR, &Handle); + + if (EFI_ERROR (Status)) { + continue; + } + + if (CapsuleInstance - 1 == RecoveryCapsuleCount) { + // + // Get file size + // + *Size = (UINTN) (((PEI_FAT_FILE *) Handle)->FileSize); + + // + // Find corresponding physical block device + // + BlockDeviceNo = PrivateData->Volume[Index].BlockDeviceNo; + while (PrivateData->BlockDevice[BlockDeviceNo].Logical && BlockDeviceNo < PrivateData->BlockDeviceCount) { + BlockDeviceNo = PrivateData->BlockDevice[BlockDeviceNo].ParentDevNo; + } + // + // Fill in the Capsule Type GUID according to the block device type + // + if (BlockDeviceNo < PrivateData->BlockDeviceCount) { + switch (PrivateData->BlockDevice[BlockDeviceNo].DevType) { + case LegacyFloppy: + CopyGuid (CapsuleType, &gRecoveryOnFatFloppyDiskGuid); + break; + + case IdeCDROM: + case IdeLS120: + CopyGuid (CapsuleType, &gRecoveryOnFatIdeDiskGuid); + break; + + case UsbMassStorage: + CopyGuid (CapsuleType, &gRecoveryOnFatUsbDiskGuid); + break; + + default: + break; + } + } + + return EFI_SUCCESS; + } + + RecoveryCapsuleCount++; + } + + return EFI_NOT_FOUND; +} + + +/** + Loads a DXE capsule from some media into memory. + + This function, by whatever mechanism, retrieves a DXE capsule from some device + and loads it into memory. Note that the published interface is device neutral. + + @param[in] PeiServices General-purpose services that are available + to every PEIM + @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI + instance. + @param[in] CapsuleInstance Specifies which capsule instance to retrieve. + @param[out] Buffer Specifies a caller-allocated buffer in which + the requested recovery capsule will be returned. + + @retval EFI_SUCCESS The capsule was loaded correctly. + @retval EFI_DEVICE_ERROR A device error occurred. + @retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found. + +**/ +EFI_STATUS +EFIAPI +LoadRecoveryCapsule ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This, + IN UINTN CapsuleInstance, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + PEI_FAT_PRIVATE_DATA *PrivateData; + UINTN Index; + UINTN RecoveryCapsuleCount; + PEI_FILE_HANDLE Handle; + UINTN NumberRecoveryCapsules; + + Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules); + + if (EFI_ERROR (Status)) { + return Status; + } + + if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) { + CapsuleInstance = CapsuleInstance + 1; + } + + if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) { + return EFI_NOT_FOUND; + } + + PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This); + + // + // Search each volume in the root directory for the Recovery capsule + // + RecoveryCapsuleCount = 0; + for (Index = 0; Index < PrivateData->VolumeCount; Index++) { + Status = FindRecoveryFile (PrivateData, Index, PEI_FAT_RECOVERY_CAPSULE_WITHOUT_NT_EMULATOR, &Handle); + if (EFI_ERROR (Status)) { + continue; + } + + if (CapsuleInstance - 1 == RecoveryCapsuleCount) { + + Status = FatReadFile ( + PrivateData, + Handle, + (UINTN) (((PEI_FAT_FILE *) Handle)->FileSize), + Buffer + ); + return Status; + } + + RecoveryCapsuleCount++; + } + + return EFI_NOT_FOUND; +} + + +/** + Finds the recovery file on a FAT volume. + This function finds the the recovery file named FileName on a specified FAT volume and returns + its FileHandle pointer. + + @param PrivateData Global memory map for accessing global + variables. + @param VolumeIndex The index of the volume. + @param FileName The recovery file name to find. + @param Handle The output file handle. + + @retval EFI_DEVICE_ERROR Some error occured when operating the FAT + volume. + @retval EFI_NOT_FOUND The recovery file was not found. + @retval EFI_SUCCESS The recovery file was successfully found on the + FAT volume. + +**/ +EFI_STATUS +FindRecoveryFile ( + IN PEI_FAT_PRIVATE_DATA *PrivateData, + IN UINTN VolumeIndex, + IN CHAR16 *FileName, + OUT PEI_FILE_HANDLE *Handle + ) +{ + EFI_STATUS Status; + PEI_FAT_FILE Parent; + PEI_FAT_FILE *File; + + File = &PrivateData->File; + + // + // VolumeIndex must be less than PEI_FAT_MAX_VOLUME because PrivateData->VolumeCount + // cannot be larger than PEI_FAT_MAX_VOLUME when detecting recovery volume. + // + ASSERT (VolumeIndex < PEI_FAT_MAX_VOLUME); + + // + // Construct root directory file + // + ZeroMem (&Parent, sizeof (PEI_FAT_FILE)); + Parent.IsFixedRootDir = (BOOLEAN) ((PrivateData->Volume[VolumeIndex].FatType == Fat32) ? FALSE : TRUE); + Parent.Attributes = FAT_ATTR_DIRECTORY; + Parent.CurrentPos = 0; + Parent.CurrentCluster = Parent.IsFixedRootDir ? 0 : PrivateData->Volume[VolumeIndex].RootDirCluster; + Parent.StartingCluster = Parent.CurrentCluster; + Parent.Volume = &PrivateData->Volume[VolumeIndex]; + + Status = FatSetFilePos (PrivateData, &Parent, 0); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + // + // Search for recovery capsule in root directory + // + Status = FatReadNextDirectoryEntry (PrivateData, &Parent, File); + while (Status == EFI_SUCCESS) { + // + // Compare whether the file name is recovery file name. + // + if (EngStriColl (PrivateData, FileName, File->FileName)) { + break; + } + + Status = FatReadNextDirectoryEntry (PrivateData, &Parent, File); + } + + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + // + // Get the recovery file, set its file position to 0. + // + if (File->StartingCluster != 0) { + Status = FatSetFilePos (PrivateData, File, 0); + } + + *Handle = File; + + return EFI_SUCCESS; + +} diff --git a/FatPkg/FatPei/FatLiteApi.h b/FatPkg/FatPei/FatLiteApi.h new file mode 100644 index 0000000..3568d04 --- /dev/null +++ b/FatPkg/FatPei/FatLiteApi.h @@ -0,0 +1,27 @@ +/** @file + Definitions for FAT recovery PEIM API functions + +Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+ +This program and the accompanying materials +are licensed and made available under the terms and conditions of the Software +License Agreement which accompanies this distribution. + +**/ + +#ifndef _FAT_API_H_ +#define _FAT_API_H_ + +// +// API data structures +// +typedef VOID *PEI_FILE_HANDLE; + +typedef enum { + Fat12, + Fat16, + Fat32, + FatUnknown +} PEI_FAT_TYPE; + +#endif diff --git a/FatPkg/FatPei/FatLiteFmt.h b/FatPkg/FatPei/FatLiteFmt.h new file mode 100644 index 0000000..e523a86 --- /dev/null +++ b/FatPkg/FatPei/FatLiteFmt.h @@ -0,0 +1,140 @@ +/** @file + FAT format data structures + +Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.
+ +This program and the accompanying materials +are licensed and made available under the terms and conditions of the Software +License Agreement which accompanies this distribution. + +**/ + +#ifndef _FAT_FMT_H_ +#define _FAT_FMT_H_ + +// +// Definitions +// +#define FAT_ATTR_READ_ONLY 0x01 +#define FAT_ATTR_HIDDEN 0x02 +#define FAT_ATTR_SYSTEM 0x04 +#define FAT_ATTR_VOLUME_ID 0x08 +#define FAT_ATTR_DIRECTORY 0x10 +#define FAT_ATTR_ARCHIVE 0x20 +#define FAT_ATTR_LFN (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID) + +#define FAT_CLUSTER_SPECIAL ((-1 &~0xF) | 0x7) +#define FAT_CLUSTER_FREE 0 +#define FAT_CLUSTER_RESERVED (FAT_CLUSTER_SPECIAL) +#define FAT_CLUSTER_BAD (FAT_CLUSTER_SPECIAL) +#define FAT_CLUSTER_LAST (-1) + +#define DELETE_ENTRY_MARK 0xE5 +#define EMPTY_ENTRY_MARK 0x00 + +#define FAT_CLUSTER_FUNCTIONAL(Cluster) (((Cluster) == 0) || ((Cluster) >= FAT_CLUSTER_SPECIAL)) +#define FAT_CLUSTER_END_OF_CHAIN(Cluster) ((Cluster) > (FAT_CLUSTER_SPECIAL)) + +// +// Directory Entry +// +#pragma pack(1) + +typedef struct { + UINT16 Day : 5; + UINT16 Month : 4; + UINT16 Year : 7; // From 1980 +} FAT_DATE; + +typedef struct { + UINT16 DoubleSecond : 5; + UINT16 Minute : 6; + UINT16 Hour : 5; +} FAT_TIME; + +typedef struct { + FAT_TIME Time; + FAT_DATE Date; +} FAT_DATE_TIME; + +typedef struct { + CHAR8 FileName[11]; // 8.3 filename + UINT8 Attributes; + UINT8 CaseFlag; + UINT8 CreateMillisecond; // (creation milliseconds - ignored) + FAT_DATE_TIME FileCreateTime; + FAT_DATE FileLastAccess; + UINT16 FileClusterHigh; // >= FAT32 + FAT_DATE_TIME FileModificationTime; + UINT16 FileCluster; + UINT32 FileSize; +} FAT_DIRECTORY_ENTRY; + +#pragma pack() +// +// Boot Sector +// +#pragma pack(1) + +typedef struct { + + UINT8 Ia32Jump[3]; + CHAR8 OemId[8]; + + UINT16 SectorSize; + UINT8 SectorsPerCluster; + UINT16 ReservedSectors; + UINT8 NoFats; + UINT16 RootEntries; // < FAT32, root dir is fixed size + UINT16 Sectors; + UINT8 Media; // (ignored) + UINT16 SectorsPerFat; // < FAT32 + UINT16 SectorsPerTrack; // (ignored) + UINT16 Heads; // (ignored) + UINT32 HiddenSectors; // (ignored) + UINT32 LargeSectors; // => FAT32 + UINT8 PhysicalDriveNumber; // (ignored) + UINT8 CurrentHead; // holds boot_sector_dirty bit + UINT8 Signature; // (ignored) + CHAR8 Id[4]; + CHAR8 FatLabel[11]; + CHAR8 SystemId[8]; + +} PEI_FAT_BOOT_SECTOR; + +typedef struct { + + UINT8 Ia32Jump[3]; + CHAR8 OemId[8]; + + UINT16 SectorSize; + UINT8 SectorsPerCluster; + UINT16 ReservedSectors; + UINT8 NoFats; + UINT16 RootEntries; // < FAT32, root dir is fixed size + UINT16 Sectors; + UINT8 Media; // (ignored) + UINT16 SectorsPerFat; // < FAT32 + UINT16 SectorsPerTrack; // (ignored) + UINT16 Heads; // (ignored) + UINT32 HiddenSectors; // (ignored) + UINT32 LargeSectors; // Used if Sectors==0 + UINT32 LargeSectorsPerFat; // FAT32 + UINT16 ExtendedFlags; // FAT32 (ignored) + UINT16 FsVersion; // FAT32 (ignored) + UINT32 RootDirFirstCluster; // FAT32 + UINT16 FsInfoSector; // FAT32 + UINT16 BackupBootSector; // FAT32 + UINT8 Reserved[12]; // FAT32 (ignored) + UINT8 PhysicalDriveNumber; // (ignored) + UINT8 CurrentHead; // holds boot_sector_dirty bit + UINT8 Signature; // (ignored) + CHAR8 Id[4]; + CHAR8 FatLabel[11]; + CHAR8 SystemId[8]; + +} PEI_FAT_BOOT_SECTOR_EX; + +#pragma pack() + +#endif diff --git a/FatPkg/FatPei/FatLiteLib.c b/FatPkg/FatPei/FatLiteLib.c new file mode 100644 index 0000000..4789e10 --- /dev/null +++ b/FatPkg/FatPei/FatLiteLib.c @@ -0,0 +1,361 @@ +/** @file + General purpose supporting routines for FAT recovery PEIM + +Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.
+ +This program and the accompanying materials +are licensed and made available under the terms and conditions of the Software +License Agreement which accompanies this distribution. + +**/ + +#include "FatLitePeim.h" + + +#define CHAR_FAT_VALID 0x01 + + +/** + Converts a union code character to upper case. + This functions converts a unicode character to upper case. + If the input Letter is not a lower-cased letter, + the original value is returned. + + @param Letter The input unicode character. + + @return The upper cased letter. + +**/ +CHAR16 +ToUpper ( + IN CHAR16 Letter + ) +{ + if ('a' <= Letter && Letter <= 'z') { + Letter = (CHAR16) (Letter - 0x20); + } + + return Letter; +} + + +/** + Reads a block of data from the block device by calling + underlying Block I/O service. + + @param PrivateData Global memory map for accessing global variables + @param BlockDeviceNo The index for the block device number. + @param Lba The logic block address to read data from. + @param BufferSize The size of data in byte to read. + @param Buffer The buffer of the + + @retval EFI_DEVICE_ERROR The specified block device number exceeds the maximum + device number. + @retval EFI_DEVICE_ERROR The maximum address has exceeded the maximum address + of the block device. + +**/ +EFI_STATUS +FatReadBlock ( + IN PEI_FAT_PRIVATE_DATA *PrivateData, + IN UINTN BlockDeviceNo, + IN EFI_PEI_LBA Lba, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + PEI_FAT_BLOCK_DEVICE *BlockDev; + + if (BlockDeviceNo > PEI_FAT_MAX_BLOCK_DEVICE - 1) { + return EFI_DEVICE_ERROR; + } + + Status = EFI_SUCCESS; + BlockDev = &(PrivateData->BlockDevice[BlockDeviceNo]); + + if (BufferSize > MultU64x32 (BlockDev->LastBlock - Lba + 1, BlockDev->BlockSize)) { + return EFI_DEVICE_ERROR; + } + + if (!BlockDev->Logical) { + // + // Status = BlockDev->ReadFunc + // (PrivateData->PeiServices, BlockDev->PhysicalDevNo, Lba, BufferSize, Buffer); + // + Status = BlockDev->BlockIo->ReadBlocks ( + (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (), + BlockDev->BlockIo, + BlockDev->PhysicalDevNo, + Lba, + BufferSize, + Buffer + ); + + } else { + Status = FatReadDisk ( + PrivateData, + BlockDev->ParentDevNo, + BlockDev->StartingPos + MultU64x32 (Lba, BlockDev->BlockSize), + BufferSize, + Buffer + ); + } + + return Status; +} + + +/** + Find a cache block designated to specific Block device and Lba. + If not found, invalidate an oldest one and use it. (LRU cache) + + @param PrivateData the global memory map. + @param BlockDeviceNo the Block device. + @param Lba the Logical Block Address + @param CachePtr Ptr to the starting address of the memory holding the + data; + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_DEVICE_ERROR Something error while accessing media. + +**/ +EFI_STATUS +FatGetCacheBlock ( + IN PEI_FAT_PRIVATE_DATA *PrivateData, + IN UINTN BlockDeviceNo, + IN UINT64 Lba, + OUT CHAR8 **CachePtr + ) +{ + EFI_STATUS Status; + PEI_FAT_CACHE_BUFFER *CacheBuffer; + INTN Index; + STATIC UINT8 Seed; + + Status = EFI_SUCCESS; + CacheBuffer = NULL; + + // + // go through existing cache buffers + // + for (Index = 0; Index < PEI_FAT_CACHE_SIZE; Index++) { + CacheBuffer = &(PrivateData->CacheBuffer[Index]); + if (CacheBuffer->Valid && CacheBuffer->BlockDeviceNo == BlockDeviceNo && CacheBuffer->Lba == Lba) { + break; + } + } + + if (Index < PEI_FAT_CACHE_SIZE) { + *CachePtr = (CHAR8 *) CacheBuffer->Buffer; + return EFI_SUCCESS; + } + // + // We have to find an invalid cache buffer + // + for (Index = 0; Index < PEI_FAT_CACHE_SIZE; Index++) { + if (!PrivateData->CacheBuffer[Index].Valid) { + break; + } + } + // + // Use the cache buffer + // + if (Index == PEI_FAT_CACHE_SIZE) { + Index = (Seed++) % PEI_FAT_CACHE_SIZE; + } + + // + // Current device ID should be less than maximum device ID. + // + if (BlockDeviceNo >= PEI_FAT_MAX_BLOCK_DEVICE) { + return EFI_DEVICE_ERROR; + } + + CacheBuffer = &(PrivateData->CacheBuffer[Index]); + + CacheBuffer->BlockDeviceNo = BlockDeviceNo; + CacheBuffer->Lba = Lba; + CacheBuffer->Size = PrivateData->BlockDevice[BlockDeviceNo].BlockSize; + + // + // Read in the data + // + Status = FatReadBlock ( + PrivateData, + BlockDeviceNo, + Lba, + CacheBuffer->Size, + CacheBuffer->Buffer + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + CacheBuffer->Valid = TRUE; + *CachePtr = (CHAR8 *) CacheBuffer->Buffer; + + return Status; +} + + +/** + Disk reading. + + @param PrivateData the global memory map; + @param BlockDeviceNo the block device to read; + @param StartingAddress the starting address. + @param Size the amount of data to read. + @param Buffer the buffer holding the data + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_DEVICE_ERROR Something error. + +**/ +EFI_STATUS +FatReadDisk ( + IN PEI_FAT_PRIVATE_DATA *PrivateData, + IN UINTN BlockDeviceNo, + IN UINT64 StartingAddress, + IN UINTN Size, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINT32 BlockSize; + CHAR8 *BufferPtr; + CHAR8 *CachePtr; + UINT32 Offset; + UINT64 Lba; + UINT64 OverRunLba; + UINTN Amount; + + Status = EFI_SUCCESS; + BufferPtr = Buffer; + BlockSize = PrivateData->BlockDevice[BlockDeviceNo].BlockSize; + + // + // Read underrun + // + Lba = DivU64x32Remainder (StartingAddress, BlockSize, &Offset); + Status = FatGetCacheBlock (PrivateData, BlockDeviceNo, Lba, &CachePtr); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + Amount = Size < (BlockSize - Offset) ? Size : (BlockSize - Offset); + CopyMem (BufferPtr, CachePtr + Offset, Amount); + + if (Size == Amount) { + return EFI_SUCCESS; + } + + Size -= Amount; + BufferPtr += Amount; + StartingAddress += Amount; + Lba += 1; + + // + // Read aligned parts + // + OverRunLba = Lba + DivU64x32Remainder (Size, BlockSize, &Offset); + + Size -= Offset; + Status = FatReadBlock (PrivateData, BlockDeviceNo, Lba, Size, BufferPtr); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + BufferPtr += Size; + + // + // Read overrun + // + if (Offset != 0) { + Status = FatGetCacheBlock (PrivateData, BlockDeviceNo, OverRunLba, &CachePtr); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + CopyMem (BufferPtr, CachePtr, Offset); + } + + return Status; +} + + +/** + This version is different from the version in Unicode collation + protocol in that this version strips off trailing blanks. + Converts an 8.3 FAT file name using an OEM character set + to a Null-terminated Unicode string. + Here does not expand DBCS FAT chars. + + @param FatSize The size of the string Fat in bytes. + @param Fat A pointer to a Null-terminated string that contains + an 8.3 file name using an OEM character set. + @param Str A pointer to a Null-terminated Unicode string. The + string must be allocated in advance to hold FatSize + Unicode characters + +**/ +VOID +EngFatToStr ( + IN UINTN FatSize, + IN CHAR8 *Fat, + OUT CHAR16 *Str + ) +{ + CHAR16 *String; + + String = Str; + // + // No DBCS issues, just expand and add null terminate to end of string + // + while (*Fat != 0 && FatSize != 0) { + if (*Fat == ' ') { + break; + } + *String = *Fat; + String += 1; + Fat += 1; + FatSize -= 1; + } + + *String = 0; +} + + +/** + Performs a case-insensitive comparison of two Null-terminated Unicode strings. + + @param PrivateData Global memory map for accessing global variables + @param Str1 First string to perform case insensitive comparison. + @param Str2 Second string to perform case insensitive comparison. + +**/ +BOOLEAN +EngStriColl ( + IN PEI_FAT_PRIVATE_DATA *PrivateData, + IN CHAR16 *Str1, + IN CHAR16 *Str2 + ) +{ + CHAR16 UpperS1; + CHAR16 UpperS2; + + UpperS1 = ToUpper (*Str1); + UpperS2 = ToUpper (*Str2); + while (*Str1 != 0) { + if (UpperS1 != UpperS2) { + return FALSE; + } + + Str1++; + Str2++; + UpperS1 = ToUpper (*Str1); + UpperS2 = ToUpper (*Str2); + } + + return (BOOLEAN) ((*Str2 != 0) ? FALSE : TRUE); +} diff --git a/FatPkg/FatPei/FatLitePeim.h b/FatPkg/FatPei/FatLitePeim.h new file mode 100644 index 0000000..c9d9058 --- /dev/null +++ b/FatPkg/FatPei/FatLitePeim.h @@ -0,0 +1,522 @@ +/** @file + Data structures for FAT recovery PEIM + +Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+ +This program and the accompanying materials +are licensed and made available under the terms and conditions of the Software +License Agreement which accompanies this distribution. + +**/ + +#ifndef _FAT_PEIM_H_ +#define _FAT_PEIM_H_ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "FatLiteApi.h" +#include "FatLiteFmt.h" + +// +// Definitions +// +#define PEI_FAT_RECOVERY_CAPSULE_WITH_NT_EMULATOR L"fv0001.fv" +#define PEI_FAT_RECOVERY_CAPSULE_WITHOUT_NT_EMULATOR L"fvmain.fv" + +#define PEI_FAT_CACHE_SIZE 4 +#define PEI_FAT_MAX_BLOCK_SIZE 8192 +#define FAT_MAX_FILE_NAME_LENGTH 128 +#define PEI_FAT_MAX_BLOCK_DEVICE 64 +#define PEI_FAT_MAX_BLOCK_IO_PPI 32 +#define PEI_FAT_MAX_VOLUME 64 + +#define PEI_FAT_MEMMORY_PAGE_SIZE 0x1000 + +// +// Data Structures +// +// +// The block device +// +typedef struct { + + UINT32 BlockSize; + UINT64 LastBlock; + UINT32 IoAlign; + BOOLEAN Logical; + BOOLEAN PartitionChecked; + + // + // Following fields only valid for logical device + // + CHAR8 PartitionFlag[8]; + UINT64 StartingPos; + UINTN ParentDevNo; + + // + // Following fields only valid for physical device + // + EFI_PEI_BLOCK_DEVICE_TYPE DevType; + // + // EFI_PEI_READ_BLOCKS ReadFunc; + // + EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIo; + UINT8 PhysicalDevNo; +} PEI_FAT_BLOCK_DEVICE; + +// +// the Volume structure +// +typedef struct { + + UINTN BlockDeviceNo; + UINTN VolumeNo; + UINT64 VolumeSize; + UINTN MaxCluster; + CHAR16 VolumeLabel[FAT_MAX_FILE_NAME_LENGTH]; + PEI_FAT_TYPE FatType; + UINT64 FatPos; + UINT32 SectorSize; + UINT32 ClusterSize; + UINT64 FirstClusterPos; + UINT64 RootDirPos; + UINT32 RootEntries; + UINT32 RootDirCluster; + +} PEI_FAT_VOLUME; + +// +// File instance +// +typedef struct { + + PEI_FAT_VOLUME *Volume; + CHAR16 FileName[FAT_MAX_FILE_NAME_LENGTH]; + + BOOLEAN IsFixedRootDir; + + UINT32 StartingCluster; + UINT32 CurrentPos; + UINT32 StraightReadAmount; + UINT32 CurrentCluster; + + UINT8 Attributes; + UINT32 FileSize; + +} PEI_FAT_FILE; + +// +// Cache Buffer +// +typedef struct { + + BOOLEAN Valid; + UINTN BlockDeviceNo; + UINT64 Lba; + UINT32 Lru; + UINT64 Buffer[PEI_FAT_MAX_BLOCK_SIZE / 8]; + UINTN Size; + +} PEI_FAT_CACHE_BUFFER; + +// +// Private Data. +// This structure abstracts the whole memory usage in FAT PEIM. +// The entry point routine will get a chunk of memory (by whatever +// means) whose size is sizeof(PEI_FAT_PRIVATE_DATA), which is clean +// in both 32 and 64 bit environment. The boundary of the memory chunk +// should be 64bit aligned. +// +#define PEI_FAT_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('p', 'f', 'a', 't') + +typedef struct { + + UINTN Signature; + EFI_PEI_DEVICE_RECOVERY_MODULE_PPI DeviceRecoveryPpi; + EFI_PEI_PPI_DESCRIPTOR PpiDescriptor; + EFI_PEI_NOTIFY_DESCRIPTOR NotifyDescriptor; + + UINT8 UnicodeCaseMap[0x300]; + CHAR8 *EngUpperMap; + CHAR8 *EngLowerMap; + CHAR8 *EngInfoMap; + + UINT64 BlockData[PEI_FAT_MAX_BLOCK_SIZE / 8]; + UINTN BlockDeviceCount; + PEI_FAT_BLOCK_DEVICE BlockDevice[PEI_FAT_MAX_BLOCK_DEVICE]; + UINTN VolumeCount; + PEI_FAT_VOLUME Volume[PEI_FAT_MAX_VOLUME]; + PEI_FAT_FILE File; + PEI_FAT_CACHE_BUFFER CacheBuffer[PEI_FAT_CACHE_SIZE]; + +} PEI_FAT_PRIVATE_DATA; + +#define PEI_FAT_PRIVATE_DATA_FROM_THIS(a) \ + CR (a, PEI_FAT_PRIVATE_DATA, DeviceRecoveryPpi, PEI_FAT_PRIVATE_DATA_SIGNATURE) + +// +// Extract INT32 from char array +// +#define UNPACK_INT32(a) \ + (INT32) ((((UINT8 *) a)[0] << 0) | (((UINT8 *) a)[1] << 8) | (((UINT8 *) a)[2] << 16) | (((UINT8 *) a)[3] << 24)) + +// +// Extract UINT32 from char array +// +#define UNPACK_UINT32(a) \ + (UINT32) ((((UINT8 *) a)[0] << 0) | (((UINT8 *) a)[1] << 8) | (((UINT8 *) a)[2] << 16) | (((UINT8 *) a)[3] << 24)) + + +// +// API functions +// + +/** + Finds the recovery file on a FAT volume. + This function finds the the recovery file named FileName on a specified FAT volume and returns + its FileHandle pointer. + + @param PrivateData Global memory map for accessing global + variables. + @param VolumeIndex The index of the volume. + @param FileName The recovery file name to find. + @param Handle The output file handle. + + @retval EFI_DEVICE_ERROR Some error occured when operating the FAT + volume. + @retval EFI_NOT_FOUND The recovery file was not found. + @retval EFI_SUCCESS The recovery file was successfully found on the + FAT volume. + +**/ +EFI_STATUS +FindRecoveryFile ( + IN PEI_FAT_PRIVATE_DATA *PrivateData, + IN UINTN VolumeIndex, + IN CHAR16 *FileName, + OUT PEI_FILE_HANDLE *Handle + ); + + +/** + Returns the number of DXE capsules residing on the device. + This function, by whatever mechanism, searches for DXE capsules from the associated device and + returns the number and maximum size in bytes of the capsules discovered.Entry 1 is assumed to be + the highest load priority and entry N is assumed to be the lowest priority. + + @param PeiServices General-purpose services that are available to + every PEIM. + @param This Indicates the + EFI_PEI_DEVICE_RECOVERY_MODULE_PPI instance. + @param NumberRecoveryCapsules Pointer to a caller-allocated UINTN.On output, + *NumberRecoveryCapsules contains the number of + recovery capsule images available for retrieval + from this PEIM instance. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +EFIAPI +GetNumberRecoveryCapsules ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This, + OUT UINTN *NumberRecoveryCapsules + ); + + +/** + Returns the size and type of the requested recovery capsule. + This function returns the size and type of the capsule specified by CapsuleInstance. + + @param PeiServices General-purpose services that are available to + every PEIM. + @param This Indicates the + EFI_PEI_DEVICE_RECOVERY_MODULE_PPI instance. + @param CapsuleInstance Specifies for which capsule instance to + retrieve the information.T his parameter must + be between one and the value returned by + GetNumberRecoveryCapsules() in + NumberRecoveryCapsules. + @param Size A pointer to a caller-allocated UINTN in which + the size of the requested recovery module is + returned. + @param CapsuleType A pointer to a caller-allocated EFI_GUID in + which the type of the requested recovery + capsule is returned.T he semantic meaning of + the value returned is defined by the + implementation. + + @retval EFI_SUCCESS The capsule type and size were retrieved. + @retval EFI_INVALID_PARAMETER The input CapsuleInstance does not match any + discovered recovery capsule. + +**/ +EFI_STATUS +EFIAPI +GetRecoveryCapsuleInfo ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This, + IN UINTN CapsuleInstance, + OUT UINTN *Size, + OUT EFI_GUID *CapsuleType + ); + + +/** + Loads a DXE capsule from some media into memory. + + This function, by whatever mechanism, retrieves a DXE capsule from some device + and loads it into memory. Note that the published interface is device neutral. + + @param[in] PeiServices General-purpose services that are available + to every PEIM + @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI + instance. + @param[in] CapsuleInstance Specifies which capsule instance to retrieve. + @param[out] Buffer Specifies a caller-allocated buffer in which + the requested recovery capsule will be returned. + + @retval EFI_SUCCESS The capsule was loaded correctly. + @retval EFI_DEVICE_ERROR A device error occurred. + @retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found. + +**/ +EFI_STATUS +EFIAPI +LoadRecoveryCapsule ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This, + IN UINTN CapsuleInstance, + OUT VOID *Buffer + ); + + +/** + This version is different from the version in Unicode collation + protocol in that this version strips off trailing blanks. + Converts an 8.3 FAT file name using an OEM character set + to a Null-terminated Unicode string. + Here does not expand DBCS FAT chars. + + @param FatSize The size of the string Fat in bytes. + @param Fat A pointer to a Null-terminated string that contains + an 8.3 file name using an OEM character set. + @param Str A pointer to a Null-terminated Unicode string. The + string must be allocated in advance to hold FatSize + Unicode characters + +**/ +VOID +EngFatToStr ( + IN UINTN FatSize, + IN CHAR8 *Fat, + OUT CHAR16 *Str + ); + + +/** + Performs a case-insensitive comparison of two Null-terminated Unicode strings. + + @param PrivateData Global memory map for accessing global variables + @param Str1 First string to perform case insensitive comparison. + @param Str2 Second string to perform case insensitive comparison. + +**/ +BOOLEAN +EngStriColl ( + IN PEI_FAT_PRIVATE_DATA *PrivateData, + IN CHAR16 *Str1, + IN CHAR16 *Str2 + ); + + +/** + Reads a block of data from the block device by calling + underlying Block I/O service. + + @param PrivateData Global memory map for accessing global variables + @param BlockDeviceNo The index for the block device number. + @param Lba The logic block address to read data from. + @param BufferSize The size of data in byte to read. + @param Buffer The buffer of the + + @retval EFI_DEVICE_ERROR The specified block device number exceeds the maximum + device number. + @retval EFI_DEVICE_ERROR The maximum address has exceeded the maximum address + of the block device. + +**/ +EFI_STATUS +FatReadBlock ( + IN PEI_FAT_PRIVATE_DATA *PrivateData, + IN UINTN BlockDeviceNo, + IN EFI_PEI_LBA Lba, + IN UINTN BufferSize, + OUT VOID *Buffer + ); + + +/** + Check if there is a valid FAT in the corresponding Block device + of the volume and if yes, fill in the relevant fields for the + volume structure. Note there should be a valid Block device number + already set. + + @param PrivateData Global memory map for accessing global + variables. + @param Volume On input, the BlockDeviceNumber field of the + Volume should be a valid value. On successful + output, all fields except the VolumeNumber + field is initialized. + + @retval EFI_SUCCESS A FAT is found and the volume structure is + initialized. + @retval EFI_NOT_FOUND There is no FAT on the corresponding device. + @retval EFI_DEVICE_ERROR There is something error while accessing device. + +**/ +EFI_STATUS +FatGetBpbInfo ( + IN PEI_FAT_PRIVATE_DATA *PrivateData, + IN OUT PEI_FAT_VOLUME *Volume + ); + + +/** + Gets the next cluster in the cluster chain. + + @param PrivateData Global memory map for accessing global variables + @param Volume The volume + @param Cluster The cluster + @param NextCluster The cluster number of the next cluster + + @retval EFI_SUCCESS The address is got + @retval EFI_INVALID_PARAMETER ClusterNo exceeds the MaxCluster of the volume. + @retval EFI_DEVICE_ERROR Read disk error + +**/ +EFI_STATUS +FatGetNextCluster ( + IN PEI_FAT_PRIVATE_DATA *PrivateData, + IN PEI_FAT_VOLUME *Volume, + IN UINT32 Cluster, + OUT UINT32 *NextCluster + ); + + +/** + Disk reading. + + @param PrivateData the global memory map; + @param BlockDeviceNo the block device to read; + @param StartingAddress the starting address. + @param Size the amount of data to read. + @param Buffer the buffer holding the data + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_DEVICE_ERROR Something error. + +**/ +EFI_STATUS +FatReadDisk ( + IN PEI_FAT_PRIVATE_DATA *PrivateData, + IN UINTN BlockDeviceNo, + IN UINT64 StartingAddress, + IN UINTN Size, + OUT VOID *Buffer + ); + + +/** + Set a file's CurrentPos and CurrentCluster, then compute StraightReadAmount. + + @param PrivateData the global memory map + @param File the file + @param Pos the Position which is offset from the file's + CurrentPos + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Pos is beyond file's size. + @retval EFI_DEVICE_ERROR Something error while accessing media. + +**/ +EFI_STATUS +FatSetFilePos ( + IN PEI_FAT_PRIVATE_DATA *PrivateData, + IN PEI_FAT_FILE *File, + IN UINT32 Pos + ); + + +/** + Reads file data. Updates the file's CurrentPos. + + @param PrivateData Global memory map for accessing global variables + @param File The file. + @param Size The amount of data to read. + @param Buffer The buffer storing the data. + + @retval EFI_SUCCESS The data is read. + @retval EFI_INVALID_PARAMETER File is invalid. + @retval EFI_DEVICE_ERROR Something error while accessing media. + +**/ +EFI_STATUS +FatReadFile ( + IN PEI_FAT_PRIVATE_DATA *PrivateData, + IN PEI_FAT_FILE *File, + IN UINTN Size, + OUT VOID *Buffer + ); + + +/** + This function reads the next item in the parent directory and + initializes the output parameter SubFile (CurrentPos is initialized to 0). + The function updates the CurrentPos of the parent dir to after the item read. + If no more items were found, the function returns EFI_NOT_FOUND. + + @param PrivateData Global memory map for accessing global variables + @param ParentDir The parent directory. + @param SubFile The File structure containing the sub file that + is caught. + + @retval EFI_SUCCESS The next sub file is obtained. + @retval EFI_INVALID_PARAMETER The ParentDir is not a directory. + @retval EFI_NOT_FOUND No more sub file exists. + @retval EFI_DEVICE_ERROR Something error while accessing media. + +**/ +EFI_STATUS +FatReadNextDirectoryEntry ( + IN PEI_FAT_PRIVATE_DATA *PrivateData, + IN PEI_FAT_FILE *ParentDir, + OUT PEI_FAT_FILE *SubFile + ); + + +/** + This function finds partitions (logical devices) in physical block devices. + + @param PrivateData Global memory map for accessing global variables. + +**/ +VOID +FatFindPartitions ( + IN PEI_FAT_PRIVATE_DATA *PrivateData + ); + +#endif // _FAT_PEIM_H_ diff --git a/FatPkg/FatPei/FatPei.inf b/FatPkg/FatPei/FatPei.inf new file mode 100644 index 0000000..1cc9239 --- /dev/null +++ b/FatPkg/FatPei/FatPei.inf @@ -0,0 +1,103 @@ +## @file +# Lite Fat driver only used in Pei Phase. +# +# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.
+# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# Neither the name of Intel nor the names of its contributors may +# be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Additional terms: In addition to the forgoing, redistribution and use +# of the code is conditioned upon the FAT 32 File System Driver and all +# derivative works thereof being used for and designed only to read +# and/or write to a file system that is directly managed by an +# Extensible Firmware Interface (EFI) implementation or by an emulator +# of an EFI implementation. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = FatPei + MODULE_UNI_FILE = FatPei.uni + FILE_GUID = 5B60CCFD-1011-4BCF-B7D1-BB99CA96A603 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + + ENTRY_POINT = FatPeimEntry + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + Part.c + FatLiteApi.c + FatLiteLib.c + FatLiteAccess.c + FatLiteApi.h + FatLitePeim.h + FatLiteFmt.h + + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + + +[LibraryClasses] + PcdLib + BaseMemoryLib + PeimEntryPoint + BaseLib + DebugLib + PeiServicesTablePointerLib + PeiServicesLib + + +[Guids] + gRecoveryOnFatUsbDiskGuid ## SOMETIMES_CONSUMES ## UNDEFINED + gRecoveryOnFatIdeDiskGuid ## SOMETIMES_CONSUMES ## UNDEFINED + gRecoveryOnFatFloppyDiskGuid ## SOMETIMES_CONSUMES ## UNDEFINED + + +[Ppis] + gEfiPeiVirtualBlockIoPpiGuid # PPI_NOTIFY SOMETIMES_CONSUMED + gEfiPeiDeviceRecoveryModulePpiGuid # SOMETIMES_PRODUCED + + +[FeaturePcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdFrameworkCompatibilitySupport ## CONSUMES + + +[Depex] + gEfiPeiMemoryDiscoveredPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid + +[UserExtensions.TianoCore."ExtraFiles"] + FatPeiExtra.uni diff --git a/FatPkg/FatPei/FatPei.uni b/FatPkg/FatPei/FatPei.uni new file mode 100644 index 0000000000000000000000000000000000000000..f7a765cab4c4e08713b2c50543c9358c6b2bb83e GIT binary patch literal 4620 zcmd6rUr$>{5XJYoQoq9$d7)Jj+BE7zT2(c+DM-eqwh7Hsgl!;J!60Kw`SNYfZ;qF} z4knG%s){V*-MzarXU_cDx%~atR@zFHzF+H8rJvJjnx^w~lD!6Hb2*shMu#d$i9x*Nmx4% zjwZ7D$F!aL>8CZ;_k*#i_Af%pNGxUzm9))*Pcxf&y_WtP?H=oF*)s~(kF}03P6O?Q ztMLlk;myFBz1~ubUvrFl$XA60H zDhanjLPi$%pmo2 z;|s}xp zhF#gtozU04w{IsHDwrCQbs!miq1cnWL&;#q>Y;uQw11$}FlR4f=^(6bXatUy>L{Fb z^%t9A^|iiuhByFYN1tNpLmwAJJw*(7!C-GZ=4F@$8N6bDCuX+Lp2oxA1$k3wU>lt4 z)|z@kM1mT;PivkVhzBH~hbNAk_A*Lf=1r{D@xt1#;?NR(5;P5+YA8~OxGHT1o_`-h z&MN$et$4-kJ6Z->-O4O}Nvz@L(_1s_QXR@U&FMx}9 zpqAhl%b<1`(~+LTIh+t{%v^19*5ztOowB|7INP1;i@7TtnH8QQ@nOYwoI8`zg!dbY z7iu?n@IsLRa#st`tyZHFg;cE7ELeYsH`HO)`&zmNZaVHjy7E_=aevcwtnOqN_iVn& z-N~P6jlS(HqLjPwv7RFLG5LM0@a0}O%Pn27JJpAssXO@_-JW#m1<{UJ#5>>V{fW0i zzcIr9oh-vfZuM5&!TBvQzsbPEd95;)uE3p`d+pn}$A6c!tQCumpRUAAWDDI*_~y@g zkjqVfCgirGyr-I9B*J~+$7gf@mwSklz<@`N_08|cbRczWVb$+DW)ttAVJtrUc1(9g z2Y0r_Gm7^#)(V1l`ZM^O1@@6nq8)~bn%osRavV#ilIYHSQxQ$YBFm=QeHEwI^|@xM z=%=USO^7!OxS7`wnR8HbXCVLM(n~fJtN7o-R>)+H?-SYQ4%F{~u1s%L_o?UH;qCNR zQRbRY-{P88N&C9blfaIwnt<*XFxBtc1xVPrhEa6_J=b-kLJL2=Q`x0bG%+V zaUujS$g+KRcXsB?nc3O7fBm_Ywo;|<*ZNfH=X9PXX`0T`m+1@5vbK|s(k$(3ZlX~y zU8NJvOf~vLbElfCwccoana1fx<0CyW-x`8(11yztOizp9Ae?`Y~;%Vfty| zVZk#DiHYRx&vCldlPwglZbM%c{#JUvl2jwqXR?+(KaSNS&EISGJkVZ97H{sfHj}qi z%$6~FW(!nRy3qQmWQhojXC&xAGxo0a+ei|P@C@tMnz@p<6OBBBHTGBfeu{k{f~~7S zL)X6duY0nClC3;CMfY1UcrdHnedWN1@TcjmMk$e z($%~vC@v)he&PXBcuYhqdF#k#Bv1M4+DDema7iu zdnOx|=Ezg;F&6Ba3n~ZIAdj6jw##XQJy%0&6V>7(^yZU7O*@x{J0V#;{h3+UDo!&M z=tTNlrEHOk37WgGGsN{6cM!_?J`=l3-l zr1u(iG~3bqcKV=Sb|Tf*>b_=%l6b4Rk>++a*9-Y!=x(Kc>_oON31qj^fu06>u9qUP zA?u*Q_J;oRPX4jlO~1+-`09{jKhk@e?djhL?ZYs3k7Bl--)?>3?a6XSvwh*EZW&3X z@j!?QH|X2bcQn@uTI93m|HNvgJv-X7CmloC-koD=$?Cg6JPN##`ufFZSbeWAks%Mj*wd$Y z`Z&e~(LfmkUNATsPemD~K?bk*-;0qwbfk$ectPG48rTNsy1BMi$VgCw_tjG5YVm*u z?6Bgz>CUqRWy+T`gq_8As0qp8uXhK2^jIUx|v@ced1;-GpHAQ~axf3$Y_|1OrynHMlT1DvWZr>B-4%B53C`ffdW^=oXDy!RWYpnt zK5uvrnxQ@iVi|;-Y5GV`{h`*#C9$Qh1wj&{i+pDC=817;!TNjWDVK9rrV z?DFfgkG_&~Ej>GP;EzhfxMba`Hv8#1w0!p0#hKI6RTRKQK9C2*#X6`R#&oE4IENE* zjS;-P)tLY6J-)Q&{u1Ntcdjqyu5e^lSViOGitRl2NyZY-QXb#MF+@TEkL(g zjY<|$u~tvPy8FAO`*FFOrC;Fo zJ@~r}?8n-Pbr>dVa!2IMaW0)pqkHm~%4g~oXKW(r>)5@n!*zdD?9sJH4w>Uzx|v vP=&S^ftWLKJLlD%={HehEwdra&eo^$v?sRQuVNej_QU~QE9`G9aD)ACBR-Pf literal 0 HcmV?d00001 diff --git a/FatPkg/FatPei/Part.c b/FatPkg/FatPei/Part.c new file mode 100644 index 0000000..f5b2e32 --- /dev/null +++ b/FatPkg/FatPei/Part.c @@ -0,0 +1,462 @@ +/** @file + Routines supporting partition discovery and + logical device reading + +Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.
+ +This program and the accompanying materials +are licensed and made available under the terms and conditions of the Software +License Agreement which accompanies this distribution. + +**/ + +#include +#include +#include "FatLitePeim.h" + +/** + This function finds Eltorito partitions. Main algorithm + is ported from DXE partition driver. + + @param PrivateData The global memory map + @param ParentBlockDevNo The parent block device + + @retval TRUE New partitions are detected and logical block devices + are added to block device array + @retval FALSE No New partitions are added; + +**/ +BOOLEAN +FatFindEltoritoPartitions ( + IN PEI_FAT_PRIVATE_DATA *PrivateData, + IN UINTN ParentBlockDevNo + ); + +/** + This function finds Mbr partitions. Main algorithm + is ported from DXE partition driver. + + @param PrivateData The global memory map + @param ParentBlockDevNo The parent block device + + @retval TRUE New partitions are detected and logical block devices + are added to block device array + @retval FALSE No New partitions are added; + +**/ +BOOLEAN +FatFindMbrPartitions ( + IN PEI_FAT_PRIVATE_DATA *PrivateData, + IN UINTN ParentBlockDevNo + ); + + +/** + This function finds partitions (logical devices) in physical block devices. + + @param PrivateData Global memory map for accessing global variables. + +**/ +VOID +FatFindPartitions ( + IN PEI_FAT_PRIVATE_DATA *PrivateData + ) +{ + BOOLEAN Found; + UINTN Index; + + do { + Found = FALSE; + + for (Index = 0; Index < PrivateData->BlockDeviceCount; Index++) { + if (!PrivateData->BlockDevice[Index].PartitionChecked) { + Found = FatFindMbrPartitions (PrivateData, Index); + if (!Found) { + Found = FatFindEltoritoPartitions (PrivateData, Index); + } + } + } + } while (Found && PrivateData->BlockDeviceCount <= PEI_FAT_MAX_BLOCK_DEVICE); +} + + +/** + This function finds Eltorito partitions. Main algorithm + is ported from DXE partition driver. + + @param PrivateData The global memory map + @param ParentBlockDevNo The parent block device + + @retval TRUE New partitions are detected and logical block devices + are added to block device array + @retval FALSE No New partitions are added; + +**/ +BOOLEAN +FatFindEltoritoPartitions ( + IN PEI_FAT_PRIVATE_DATA *PrivateData, + IN UINTN ParentBlockDevNo + ) +{ + EFI_STATUS Status; + BOOLEAN Found; + PEI_FAT_BLOCK_DEVICE *BlockDev; + PEI_FAT_BLOCK_DEVICE *ParentBlockDev; + UINT32 VolDescriptorLba; + UINT32 Lba; + CDROM_VOLUME_DESCRIPTOR *VolDescriptor; + ELTORITO_CATALOG *Catalog; + UINTN Check; + UINTN Index; + UINTN MaxIndex; + UINT16 *CheckBuffer; + UINT32 SubBlockSize; + UINT32 SectorCount; + UINT32 VolSpaceSize; + + if (ParentBlockDevNo > PEI_FAT_MAX_BLOCK_DEVICE - 1) { + return FALSE; + } + + Found = FALSE; + ParentBlockDev = &(PrivateData->BlockDevice[ParentBlockDevNo]); + VolSpaceSize = 0; + + // + // CD_ROM has the fixed block size as 2048 bytes + // + if (ParentBlockDev->BlockSize != 2048) { + return FALSE; + } + + VolDescriptor = (CDROM_VOLUME_DESCRIPTOR *) PrivateData->BlockData; + Catalog = (ELTORITO_CATALOG *) VolDescriptor; + + // + // the ISO-9660 volume descriptor starts at 32k on the media + // and CD_ROM has the fixed block size as 2048 bytes, so... + // + VolDescriptorLba = 15; + // + // ((16*2048) / Media->BlockSize) - 1; + // + // Loop: handle one volume descriptor per time + // + while (TRUE) { + + VolDescriptorLba += 1; + if (VolDescriptorLba > ParentBlockDev->LastBlock) { + // + // We are pointing past the end of the device so exit + // + break; + } + + Status = FatReadBlock ( + PrivateData, + ParentBlockDevNo, + VolDescriptorLba, + ParentBlockDev->BlockSize, + VolDescriptor + ); + if (EFI_ERROR (Status)) { + break; + } + // + // Check for valid volume descriptor signature + // + if (VolDescriptor->Unknown.Type == CDVOL_TYPE_END || + CompareMem (VolDescriptor->Unknown.Id, CDVOL_ID, sizeof (VolDescriptor->Unknown.Id)) != 0 + ) { + // + // end of Volume descriptor list + // + break; + } + // + // Read the Volume Space Size from Primary Volume Descriptor 81-88 byte + // + if (VolDescriptor->Unknown.Type == CDVOL_TYPE_CODED) { + VolSpaceSize = VolDescriptor->PrimaryVolume.VolSpaceSize[1]; + } + // + // Is it an El Torito volume descriptor? + // + if (CompareMem ( + VolDescriptor->BootRecordVolume.SystemId, + CDVOL_ELTORITO_ID, + sizeof (CDVOL_ELTORITO_ID) - 1 + ) != 0) { + continue; + } + // + // Read in the boot El Torito boot catalog + // + Lba = UNPACK_INT32 (VolDescriptor->BootRecordVolume.EltCatalog); + if (Lba > ParentBlockDev->LastBlock) { + continue; + } + + Status = FatReadBlock ( + PrivateData, + ParentBlockDevNo, + Lba, + ParentBlockDev->BlockSize, + Catalog + ); + if (EFI_ERROR (Status)) { + continue; + } + // + // We don't care too much about the Catalog header's contents, but we do want + // to make sure it looks like a Catalog header + // + if (Catalog->Catalog.Indicator != ELTORITO_ID_CATALOG || Catalog->Catalog.Id55AA != 0xAA55) { + continue; + } + + Check = 0; + CheckBuffer = (UINT16 *) Catalog; + for (Index = 0; Index < sizeof (ELTORITO_CATALOG) / sizeof (UINT16); Index += 1) { + Check += CheckBuffer[Index]; + } + + if ((Check & 0xFFFF) != 0) { + continue; + } + + MaxIndex = ParentBlockDev->BlockSize / sizeof (ELTORITO_CATALOG); + for (Index = 1; Index < MaxIndex; Index += 1) { + // + // Next entry + // + Catalog += 1; + + // + // Check this entry + // + if (Catalog->Boot.Indicator != ELTORITO_ID_SECTION_BOOTABLE || Catalog->Boot.Lba == 0) { + continue; + } + + SubBlockSize = 512; + SectorCount = Catalog->Boot.SectorCount; + + switch (Catalog->Boot.MediaType) { + + case ELTORITO_NO_EMULATION: + SubBlockSize = ParentBlockDev->BlockSize; + SectorCount = Catalog->Boot.SectorCount; + break; + + case ELTORITO_HARD_DISK: + break; + + case ELTORITO_12_DISKETTE: + SectorCount = 0x50 * 0x02 * 0x0F; + break; + + case ELTORITO_14_DISKETTE: + SectorCount = 0x50 * 0x02 * 0x12; + break; + + case ELTORITO_28_DISKETTE: + SectorCount = 0x50 * 0x02 * 0x24; + break; + + default: + SectorCount = 0; + SubBlockSize = ParentBlockDev->BlockSize; + break; + } + + if (SectorCount < 2) { + SectorCount = (VolSpaceSize > ParentBlockDev->LastBlock + 1) ? (UINT32) (ParentBlockDev->LastBlock - Catalog->Boot.Lba + 1) : (UINT32) (VolSpaceSize - Catalog->Boot.Lba); + } + // + // Register this partition + // + if (PrivateData->BlockDeviceCount < PEI_FAT_MAX_BLOCK_DEVICE) { + + Found = TRUE; + + BlockDev = &(PrivateData->BlockDevice[PrivateData->BlockDeviceCount]); + + BlockDev->BlockSize = SubBlockSize; + BlockDev->LastBlock = SectorCount - 1; + BlockDev->IoAlign = ParentBlockDev->IoAlign; + BlockDev->Logical = TRUE; + BlockDev->PartitionChecked = FALSE; + BlockDev->StartingPos = MultU64x32 (Catalog->Boot.Lba, ParentBlockDev->BlockSize); + BlockDev->ParentDevNo = ParentBlockDevNo; + + PrivateData->BlockDeviceCount++; + } + } + } + + ParentBlockDev->PartitionChecked = TRUE; + + return Found; + +} + + +/** + Test to see if the Mbr buffer is a valid MBR + + @param Mbr Parent Handle + @param LastLba Last Lba address on the device. + + @retval TRUE Mbr is a Valid MBR + @retval FALSE Mbr is not a Valid MBR + +**/ +BOOLEAN +PartitionValidMbr ( + IN MASTER_BOOT_RECORD *Mbr, + IN EFI_PEI_LBA LastLba + ) +{ + UINT32 StartingLBA; + UINT32 EndingLBA; + UINT32 NewEndingLBA; + INTN Index1; + INTN Index2; + BOOLEAN MbrValid; + + if (Mbr->Signature != MBR_SIGNATURE) { + return FALSE; + } + // + // The BPB also has this signature, so it can not be used alone. + // + MbrValid = FALSE; + for (Index1 = 0; Index1 < MAX_MBR_PARTITIONS; Index1++) { + if (Mbr->Partition[Index1].OSIndicator == 0x00 || UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) == 0) { + continue; + } + + MbrValid = TRUE; + StartingLBA = UNPACK_UINT32 (Mbr->Partition[Index1].StartingLBA); + EndingLBA = StartingLBA + UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) - 1; + if (EndingLBA > LastLba) { + // + // Compatability Errata: + // Some systems try to hide drive space with thier INT 13h driver + // This does not hide space from the OS driver. This means the MBR + // that gets created from DOS is smaller than the MBR created from + // a real OS (NT & Win98). This leads to BlockIo->LastBlock being + // wrong on some systems FDISKed by the OS. + // + // return FALSE Because no block devices on a system are implemented + // with INT 13h + // + return FALSE; + } + + for (Index2 = Index1 + 1; Index2 < MAX_MBR_PARTITIONS; Index2++) { + if (Mbr->Partition[Index2].OSIndicator == 0x00 || UNPACK_INT32 (Mbr->Partition[Index2].SizeInLBA) == 0) { + continue; + } + + NewEndingLBA = UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) + UNPACK_UINT32 (Mbr->Partition[Index2].SizeInLBA) - 1; + if (NewEndingLBA >= StartingLBA && UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) <= EndingLBA) { + // + // This region overlaps with the Index1'th region + // + return FALSE; + } + } + } + // + // Non of the regions overlapped so MBR is O.K. + // + return MbrValid; +} + + +/** + This function finds Mbr partitions. Main algorithm + is ported from DXE partition driver. + + @param PrivateData The global memory map + @param ParentBlockDevNo The parent block device + + @retval TRUE New partitions are detected and logical block devices + are added to block device array + @retval FALSE No New partitions are added; + +**/ +BOOLEAN +FatFindMbrPartitions ( + IN PEI_FAT_PRIVATE_DATA *PrivateData, + IN UINTN ParentBlockDevNo + ) +{ + EFI_STATUS Status; + MASTER_BOOT_RECORD *Mbr; + UINTN Index; + BOOLEAN Found; + PEI_FAT_BLOCK_DEVICE *ParentBlockDev; + PEI_FAT_BLOCK_DEVICE *BlockDev; + + if (ParentBlockDevNo > PEI_FAT_MAX_BLOCK_DEVICE - 1) { + return FALSE; + } + + ParentBlockDev = &(PrivateData->BlockDevice[ParentBlockDevNo]); + + Found = FALSE; + Mbr = (MASTER_BOOT_RECORD *) PrivateData->BlockData; + + Status = FatReadBlock ( + PrivateData, + ParentBlockDevNo, + 0, + ParentBlockDev->BlockSize, + Mbr + ); + + if (EFI_ERROR (Status) || !PartitionValidMbr (Mbr, ParentBlockDev->LastBlock)) { + goto Done; + } + // + // We have a valid mbr - add each partition + // + for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) { + if (Mbr->Partition[Index].OSIndicator == 0x00 || UNPACK_INT32 (Mbr->Partition[Index].SizeInLBA) == 0) { + // + // Don't use null MBR entries + // + continue; + } + // + // Register this partition + // + if (PrivateData->BlockDeviceCount < PEI_FAT_MAX_BLOCK_DEVICE) { + + Found = TRUE; + + BlockDev = &(PrivateData->BlockDevice[PrivateData->BlockDeviceCount]); + + BlockDev->BlockSize = MBR_SIZE; + BlockDev->LastBlock = UNPACK_INT32 (Mbr->Partition[Index].SizeInLBA) - 1; + BlockDev->IoAlign = ParentBlockDev->IoAlign; + BlockDev->Logical = TRUE; + BlockDev->PartitionChecked = FALSE; + BlockDev->StartingPos = MultU64x32 ( + UNPACK_INT32 (Mbr->Partition[Index].StartingLBA), + ParentBlockDev->BlockSize + ); + BlockDev->ParentDevNo = ParentBlockDevNo; + + PrivateData->BlockDeviceCount++; + } + } + +Done: + + ParentBlockDev->PartitionChecked = TRUE; + return Found; +} diff --git a/FatPkg/FatPkg.dec b/FatPkg/FatPkg.dec new file mode 100644 index 0000000..bc5804c --- /dev/null +++ b/FatPkg/FatPkg.dec @@ -0,0 +1,53 @@ +## @file +# +# FAT Package +# +# FAT 32 Driver +# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.
+# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# Neither the name of Intel nor the names of its contributors may +# be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Additional terms: In addition to the forgoing, redistribution and use +# of the code is conditioned upon the FAT 32 File System Driver and all +# derivative works thereof being used for and designed only to read +# and/or write to a file system that is directly managed by an +# Extensible Firmware Interface (EFI) implementation or by an emulator +# of an EFI implementation. +# +## + +[Defines] + DEC_SPECIFICATION = 0x00010005 + PACKAGE_NAME = FatPkg + PACKAGE_UNI_FILE = FatPkg.uni + PACKAGE_GUID = 8EA68A2C-99CB-4332-85C6-DD5864EAA674 + PACKAGE_VERSION = 0.3 + +[UserExtensions.TianoCore."ExtraFiles"] + FatPkgExtra.uni diff --git a/FatPkg/FatPkg.dsc b/FatPkg/FatPkg.dsc new file mode 100644 index 0000000..483bb8d --- /dev/null +++ b/FatPkg/FatPkg.dsc @@ -0,0 +1,114 @@ +## @file +# +# Build Binary Enhanced Fat Driver Modules +# +# This Platform file is used to generate the Binary Fat Drivers +# for EDK II Prime release. +# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.
+# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# Neither the name of Intel nor the names of its contributors may +# be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Additional terms: In addition to the forgoing, redistribution and use +# of the code is conditioned upon the FAT 32 File System Driver and all +# derivative works thereof being used for and designed only to read +# and/or write to a file system that is directly managed by an +# Extensible Firmware Interface (EFI) implementation or by an emulator +# of an EFI implementation. +# +## + +[Defines] + PLATFORM_NAME = Fat + PLATFORM_GUID = 25b55dbc-9d0b-4a32-80da-46e1273d622c + PLATFORM_VERSION = 0.3 + DSC_SPECIFICATION = 0x00010005 + SUPPORTED_ARCHITECTURES = IA32|X64|IPF|EBC|ARM|AARCH64 + OUTPUT_DIRECTORY = Build/Fat + BUILD_TARGETS = DEBUG|RELEASE + SKUID_IDENTIFIER = DEFAULT + +[BuildOptions] + GCC:RELEASE_*_*_CC_FLAGS = -DMDEPKG_NDEBUG + INTEL:RELEASE_*_*_CC_FLAGS = /D MDEPKG_NDEBUG + MSFT:RELEASE_*_*_CC_FLAGS = /D MDEPKG_NDEBUG + RVCT:RELEASE_*_*_CC_FLAGS = -DMDEPKG_NDEBUG + +[LibraryClasses] + # + # Entry Point Libraries + # + UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf + # + # Common Libraries + # + BaseLib|MdePkg/Library/BaseLib/BaseLib.inf + BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf + UefiLib|MdePkg/Library/UefiLib/UefiLib.inf + PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf + PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf + UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf + DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf + DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf + DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf + +[LibraryClasses.common.PEIM] + PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf + PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf + PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf + HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf + MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf + +[LibraryClasses.ARM, LibraryClasses.AARCH64] + NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf + NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf + +################################################################################################### +# +# Components Section - list of the modules and components that will be processed by compilation +# tools and the EDK II tools to generate PE32/PE32+/Coff image files. +# +# Note: The EDK II DSC file is not used to specify how compiled binary images get placed +# into firmware volume images. This section is just a list of modules to compile from +# source into UEFI-compliant binaries. +# It is the FDF file that contains information on combining binary files into firmware +# volume images, whose concept is beyond UEFI and is described in PI specification. +# Binary modules do not need to be listed in this section, as they should be +# specified in the FDF file. For example: Shell binary (Shell_Full.efi), FAT binary (Fat.efi), +# Logo (Logo.bmp), and etc. +# There may also be modules listed in this section that are not required in the FDF file, +# When a module listed here is excluded from FDF file, then UEFI-compliant binary will be +# generated for it, but the binary will not be put into any firmware volume. +# +################################################################################################### + +[Components] + FatPkg/FatPei/FatPei.inf + FatPkg/EnhancedFatDxe/Fat.inf diff --git a/FatPkg/FatPkg.uni b/FatPkg/FatPkg.uni new file mode 100644 index 0000000000000000000000000000000000000000..b38875b5ae2e0fa6bd03a17db0a130c73b3902c4 GIT binary patch literal 4918 zcmd6r;ZGY!5XJX%rTz~m@+Ga3(596trBzj9Oh7fpwM}R~MPLH4f(ops z>FqdOKbXxBwcFsiJqpqZ>2^WH3i8fe5zFGn$EfQON=#5RG9o{8>}sh?t$FS2djF-9!8#>s+?nWelz0#9o*M zCAP6D%y3{nls~YGvCLYGqk>|hcUXW&;EMV9w35B{Z6LYNVy~CbyNWAVx|D{qj1o?! zimZa6JpC0XwsCd5+~vfcC6hSX0^$Fi8LySXN#H(~r-rg-ISCj z=6R&2v+UXBn2%KzF<-RXce6adzQR}guOqEquht&eC(;e>h^2atA_75rcWhY$NTlTm ztYcv&Z?N*F7Ewo8mvaxRd?p>0`iND}F&6Zi4e|#$A=-``>t)5kpK~G^ikvada$~iS z*-j+kT1Z%tg~8y~8H*K79vVs>d*5)bksS>**IASE6B)DQtV_-GzPFnDLE6?%)z_SU z+SA@PNC(RDJ?&rByuYi~UV5X}rg}HkzmeYRpP7tm>TOp&J&ky+KK9dX^|kZ(UY6ZR zojjAV9gSe@hIZ3|+Kec6uSq*-z_g}&%;b*NR{B-iz}L^?n9t~4^|p04Lfg>Gvj@4i zKi}m#!rPYSP4#w!m+WOEmD+nkRIng#SJz-J6|{^G%O9h)(wr^L*_Di*bZ^fwHKcVX zBOYYC!cMA-fsllKTbZGPsUcZi$>?d+j^yo21}%E`b?<6?U$bG(Uc}OVwz{DwaBM1% z!dXZE*bJ+0bm1A|0E}(@ilxgwE{OING2jJ*y>XwHVH#xciv8`}vW50E9tJPSn?eKI z;9S+$)Egoa)Zl$q^ITs%AOStRaon`#Q35k>b8j6lto>|ezrK`5$i$I({EoagOD{%b;+tf&^uy@XlP1@wUad>!WkXj zE>Yw)g;rv~EJU1?bpql8>1jzX|6cpZD>2v5vm*!o$TYM|)GbQ0oz6q`wZF>Gtd^F% z050NzIKVHKLGCc71HFfHI3d<(!P{%Kxrg=G(wN(ekHhZBFXparWL9{K#N~|bIQL3M z6W(tqUdY|x!3#wO$ek@fx0sDe6q2zPSHbFiq@g{sUe{7Ju!FJ(QkB0_i~XCbV{v5c zv$2!Al0VhXM%{Lrqm;ezzM3NHm@3z{^*z+JaL6rHuq)N&%G8zom3B|6^io^IDbc5| zE#czq3IFA+c;AT-9?oi+sZ<3%S-IA}&inYsT$LCv78^fRiJ1rssZGpMu^qYW^ru2@ zJFwv_pN(9{AQA3MJo(fb^pvvDtcGG0Un$nJO!~N<$Uaw~J_kB8z0>+5Tm7tm^2s~ho%N|)oV6<9 zSpGf9*pYQLXV`V>^PF!hRZjIU4-fNmDftmi5$W-L<=^}svUbbRW7%Q1r;;I~mYwJC surs(luP%OjDW?UWjN!)L2p;ogiPgyYnQsi`>&}0{ z*83`T(nRZ_xJT&^Q7%NQ#W~gbRy;GUhkAnE6z{FxUB-21DZOZc<1RhM?(6hxXxx_k z&$auT^i}#gy-u(6e7KM^UPzs4*F?L(I0`L0deaapIKX0QpqWblOuuRRE%5H7@6ulC zr|&o5=?BM1{I=*U-7hs1yY53?6&6=|o``EI)c7aceim@^&$c21$>_V&bt+CI;%WSTC(1;n_)43db6aIHy`sJk|xsn)L-ZXCD!6sat?iS;U%LgJsI&Zor#wi z8tHo86co4O0zdJ>Y&X3{VYlz3#CHs$v}dBhfO&XuPg zaa1qlC1+a3_kZ_`>!iddgg;Rq*HbGerk(i z`mt8M^j52us4da=(mP$*30G5Zk45Q=<44g3q8*6V3I2Y_ZlrGPgtsdWc=ytYo_cz& zS0b<_?Vv&TmhO2cceJ+CFVY6SI{4TR_mQX_-Hp&T^kerRsP*D>>k4m2np>iFg_pi% zB$d`ZAu7H>-jRNTg;dbOpDq74S}X0@*PbKE=u7v(0#id;4+HTa?8HIyl2T$Q#1&wtM$R~7NYR-$6>J6mee z_oR;)5A;k1R>IKJUn_7JIhgxVn@v5{>05Di#FJ}-%sbJlz2+Tk!e{u!a*W2gXDOyr z8Fg5k>y2oDrmw#fc^QP%G;<_Xf2w!n64}s{4r`}t`kJBhI9GDTA8ev-uRXU@mXMj zRuHt)@8Q4Oz<#EkXvf23O`eFHInJdkN%Ty7S3;7fluWMb)Okt6w=ovfiJy;tQiRdGuBB&WYZrF;FPEB)oY nIt-@|m1=S literal 0 HcmV?d00001 diff --git a/FatPkg/License.txt b/FatPkg/License.txt new file mode 100644 index 0000000..2e02d1e --- /dev/null +++ b/FatPkg/License.txt @@ -0,0 +1,40 @@ +Copyright (c) 2006, Intel Corporation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + . Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + . Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + . Neither the name of Intel nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Additional terms: In addition to the forgoing, redistribution and use +of the code is conditioned upon the FAT 32 File System Driver and all +derivative works thereof being used for and designed only to read +and/or write to a file system that is directly managed by Intel's +Extensible Firmware Initiative (EFI) Specification v. 1.0 and later +and/or the Unified Extensible Firmware Interface (UEFI) Forum's UEFI +Specifications v.2.0 and later (together the "UEFI Specifications"); +only as necessary to emulate an implementation of the UEFI Specifications; +and to create firmware, applications, utilities and/or drivers. + -- 1.8.3.1