From 4a6a1b0658a6a88167170e0a94f0e8350fcf4515 Mon Sep 17 00:00:00 2001
From: Laszlo Ersek <lersek@redhat.com>
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
<https://github.com/tianocore/edk2-FatPkg.git>, 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.<BR>
+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.<BR>
+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.<BR>
+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.<BR>
+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.<BR>
+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.<BR>
+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<NUL>) <= 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.<BR>
+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.<BR>
+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.<BR>
+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 <Uefi.h>
+
+#include <Guid/FileInfo.h>
+#include <Guid/FileSystemInfo.h>
+#include <Guid/FileSystemVolumeLabelInfo.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/DiskIo.h>
+#include <Protocol/DiskIo2.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/UnicodeCollation.h>
+
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#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.<BR>
+#
+#  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
z<FmBT*jRV-G)gy`eXWs6ep{?pb9be;McPees&t*|d7PG6_KUUj&{CzJC1tLeN2#M#
z-K+)qAEXOO=v?SK(l7HCT5+bUYjEU+-rniU+^ODAggIu9vzGTMFci{-O(()O7s^5w
z-K@}#B%`itsMT-*LufXxiZpC!wDk+g80mYdna+k|W_%{eOGz{9m>q0f=TTdQ4Po1f
z){QlS9XFZ<8!&yRu`3}%+KI-@BVb3<WA=wuJbf)muzn$SVdbebe5UKm^o2g(=<fOI
z>C5zWdZzoX<ij;~BH>0d_ze^<^rqB%W`u08VZl6O#>-=Q<-4?#2I>1X7lCe&XAmQc
zEag<}xt(~=cv)t7?sfdR)NK41b53R7Oe>5vXL+8jxz#(o1aCy0KO<+cM&<E5$(|Y2
zY=sddqtCoC%@Sb<zgcX2&=~Q|2-@H(d;}ucy2{#T@<ov&2@63NzBNt35z(|ruWC5s
z-DCV&oSaKflQH5HoY)Jqpv1O?5I6JcB%Nw5UNo%DI0_Uq&B6ja0#{gXd4HL&Xt)xq
z4_j=0_DtHumF4(I41&@!te)?I=Fd1W8#l+xA314Ojqv9Gof*rO;KZ37%MT-Y9sbDh
z$Y;-_ZOtG@@F=yI`)QuX{X}<E)J-w(S>-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^<oE7a6TIQbRy<n>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?28<Q+){PmCVvdZ_tBt%f=C
zB9;!b)uryh(bf(PXMO!*GpxSR7tas}VC?A=mfrVqAUaUQfENtrjfcDp(;$Oa?C<3#
zv(P+^hrtW-me9a9I5&;8^oEE8HF%%ZJU0{%NI(y7EN(ihD1n)`d9;of)_xR+Cec=c
zrqrrZk%C9)q`>p{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{Ty<gfrW{9Z_UCg;rv~SnxQBJOS~s^mL?`U(0>uMa-4Dx5$A%Dh<yObxmnz
zr`4f)?r-ul+0v00z(qU|2l&NgP&*9MvEIWuoDgd~!P{#+b9L*nrCiyIkKJysFUDPP
zWUTNOiT5kE#kplNn(%(9c%gQK2QP#SkXy9?U9%cR6jHI8S+IE@DYZw|`&zmNb~^UJ
zsrH~(dSd^k>uAno7W=I4<krbwXpFw?B1b8E<3l}#_c2B8ZR>leb)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-<FIPy9b*$7
z(LncOTIsIn$}U!TPBRw90zoJJl4FEZ^h9TmIFS=I-W6HoSS+1OqMZYuDx#@aWLcc&
zH}$#3ROqLt<0Qn%!p_}+$T$Zjdxrgk@tE|;hLFL(Fx%Nm#`r#web#~6InXN8JJo&a
zIeT~~y;H7Q&8Kg%npFtJrq7d%9a+m2!`7!h&-J!Y=TxmvWdGJbF<WbkKh9eAZu%1H
iW9%b;&DyTmC0_sQ|9-sl_J1Sl`D5AkPyFW-O#co8+a3o1

literal 0
HcmV?d00001

diff --git a/FatPkg/EnhancedFatDxe/FatExtra.uni b/FatPkg/EnhancedFatDxe/FatExtra.uni
new file mode 100644
index 0000000000000000000000000000000000000000..70233bc5d3e87cf2799f451676942f84eeae52b5
GIT binary patch
literal 4258
zcmd6qOK)RE5QTe<#DBQTYyuh*V0HsSIJQF~Id<@MCNry1p2os?=*A(09}k?bj@xY~
z&IrK<S+;L?S67`nRb5^8uRpibcB=IKQlBdQm@d;KP18mCJbk8F)^^iLn(4onZqk{a
zr;_+X66cz$wbE#OoyO@-;}bnG-<IsP)-K{V>&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;jB<Mgh_HOmtND__k4C}X=xskUMjXZ-jM~^4=fe5y40u6DiWP@m7
zF<Wvhu~ay^(rA|6E@sNgr`SW&jjTT93!9+CTX-eIus0K4@~P635uc<}$r3{&UCo<<
z;#yMRCmt}xej-}QTSqn{dC6brZnnFQDLA^5g=wIKktS{Z3r6hW`doR+h@*NgmYiuB
z-~XK#pOX@wjQd=1I+HiBM~x`?olnuWBpStyc#;D=Uxggc6Fp5MuFvzmoG|Y!)*ZR$
zr+Z!W`m*VhYTFt4wJd`==h1R?BKyGkRJP<l8W}nJmXWZN6?}YLWK*TQ$Cj%O=X)j_
zmFCD(?=cqanhPoi)gX_ZHMYxXgFRP6Dgo8vD)i=)LQT7rh6f>8J^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?dH0rLfgHLb<FV<r;&OK}KJSU?LkMnsW
z8lV~Kb0n5Q$eE^(<kTN)ja(ud+OlEmRE?bBNatvmEb^JcDmh>la-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<iBx8x_x0El`ZtxI=q66fv7NA?LMkNcW
zSgWUC-TmFt{kYuC(l2m(a{tkbztxDln|@<eGT*WJ7I*(X)~!azHjW(SUVN#W$Q?|+
zwF_JBfwSJy{klVa-jTY0zt_!4Z(jO}U2#Zk-snAvcQe1O!TzH>!$)rPPTarT^o>UO
z-2@({OLeJq1n$AyV?V?l{;RZQt9WeubR=dXdq`hmmWmzpa?6i}+<xH0G~S5Z!=MrF
z3qQt~JHOmNTm%NXo|CYXy}euU7FPY1V>XEn7S6<nt<qW1y^ZI1P6G>b1wl9c9{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.<BR>
+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.<BR>
+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<NUL>) <= 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.<BR>
+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.<BR>
+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.<BR>
+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.<BR>
+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.<BR>
+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.<BR>
+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.<BR>
+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.<BR>
+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.<BR>
+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.<BR>
+  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.<BR>
+
+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.<BR>
+
+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.<BR>
+
+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.<BR>
+
+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.<BR>
+
+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.<BR>
+
+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 <PiPei.h>
+
+#include <Guid/RecoveryDevice.h>
+#include <Ppi/BlockIo.h>
+#include <Ppi/DeviceRecoveryModule.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Library/PeiServicesLib.h>
+
+#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.<BR>
+#
+#  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<q|Xq9Ijtt_-srJZ!F
zQI#fXuC+h3HrMPj&2-{UqnmWCwTVVktySqjvuXUk(@CB^znA;}$!`kbmGFW2EWHa0
zHq$tLC1fwsH~M_9(X-|3+w?L$)p$=9VD-7iNSI3oe_>!6Hb2*shMu#d$i9x*Nmx4%
zjwZ7D$F!aL>8CZ;_k*#i_Af%pNGxUzm9))*Pcxf&y_WtP?H=oF*)s~(kF}03P6O?Q
z<YLXOo-JfM-oj^jj-16ksw!RR`9yn(f^p4OWFQ%RSNc2GP9(w*{=U-6rL3K5<`uL#
zS{QK-M6h)k+Gp}bB^^W$8neytXH6wSE_8m8Ue$1xXCLDaS(nmViG@02Xay(s!Ynb3
zZ3}63<YvsrX{5bGy0NatQ9&`&E-b(!aK(9iTFGAfHY0h=V*5GkUB?wHT}#7xpoEio
zEuX3yJO9LqZCoEOA97;PPQ;U=EhGHgnQ^WZ4`tjFd1@?c;ExP1`J6LpOFLZGe1`Ew
z?1S;CM(5$#hcTbC%Kop{Q2Xv-hL?I+_g`1ooUg918T(AS!JT8NUZaRWkbbzg<Ny+x
zIRfigILQ;NysO30D0G#ozL1V8c!NdG7z=vM2KB>tMLlk;myFBz1~ubUvrFl$XA60H
zDhanjLPi$<Wo})u$Y|=&SUkB_83C0UG`FG2^@*FP)U0cr%=NoSFQZ}FRqY?>%pmo2
z;|<f1s(e4Swc_;y&3fszW-YC@w7#9*=r1SP)zs4it@O3y7p)DowyU*H?C*!{M(V~%
z_I9;{z1!(fqn^ftn%x`H4jOcC=r^C_7p?8|o3w#%5c@dK?tQIx^lOB+p&zG*u{v1Z
za$Vu=NOMc8UE!sA8A+viPlyUP$lKR<xReT7_GimKMQf!qJ36y38GY&AU1DlT>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->-<CdnJk*#7tc0PbPb+X3IhgyAn@x=d=?CrVXiv@!BJWVM_6j@L
z1ZVJKIY#5yvlOqB8H2Dm=NsMtO<$iwu?#|Tn(mUUKhiT|iD+m_hqY5Ra)h%xd%HxD
za|*4*fLX|KQt|}EN7B=lUj91wkym1_aUVJGN2MW>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&C9blfaIwn<c~UQ=dh>t<*XFxBtc1xVPrhEa6_J=b-kLJL2=Q<UQKx
B#7Y1F

literal 0
HcmV?d00001

diff --git a/FatPkg/FatPei/FatPeiExtra.uni b/FatPkg/FatPei/FatPeiExtra.uni
new file mode 100644
index 0000000000000000000000000000000000000000..c498a7ea38fb4f02c4abfe888b989e4bf7dc52f7
GIT binary patch
literal 4274
zcmd6q-EUh(5XJWyiT~j$eJQ9UK;H^NIJVPNa_r#iH1w&;r)%MS=*DRXe>`x0bG%+V
zaUujS$g+KRcXsB?nc3O7fBm_Ywo;|<*ZNfH=X9PXX`0T`m+1@5vbK|s(k$(3ZlX~y
zU8NJvOf~vLbElfCwccoana1fx<0CyW-<Is9*3RNLYs~*%zfSkDcbq;+vPv(d{VV-{
zpT14srPt||p5M*2Oy@eAbS=$I;F^SuO|7(q2?>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)<FaAX-?=mK;kg6^<@6nx!|3nX>X6duY0nClC3;CMfY1UcrdHnedWN1@TcjmMk$e
z($%~vC@v)he&PXBcuYhqdF#k#Bv1M4+<lHIIJ%LAX`qCWCT;!;M(pAGTzSZdqk1Zq
zoM{=~|D6|~lM<hd`&4l{kvFhMjVSq@Ptlen8pVxxlC?ZvgdEQkJxwF7kMq5pFz+nZ
z9l6J+dtLPUvgwm*+Zp+#EQ31d(Q<Vn`@s27w&Xt=89Dowk+72$e7s*|Q>DDema7iu
zdnOx|=Ezg;F&6Ba3n~ZIAdj6jw##XQJy%0&6V>7(^yZU7O*@x{J0V#;{h3+UDo!&M
z=tTNlrEHOk37WgG<jTZZF4gKrJ9FjE(aHZ+8l_#;{8~HeG|>GsN{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<EpF3f%zwmD-7%G@r
z(zP!gL!o#leFxIPh}i@E?@PYcZkTfv@w5)FTY3UVM->##`ufFZSbeWAks%Mj*wd$Y
z`Z&e~(LfmkUNATsPemD~K?bk*-;0qwbfk$ectPG48rTNsy1BMi$VgCw_tjG5YVm*u
z?6Bgz>CUqRW<JF1GG18wMI2hAcY>y+T`gq_8As0qp8uXhK2^jIUx|v@ced1;-<CaM
zJkm26SP8>GpHAQ~axf3$Y_|1OrynHMlT1DvWZr>B-4%B53C`ffdW^=oXDy!RWYpnt
zK5uvrnxQ@iVi|;-Y5GV`{h`*#C9<I{8@5i>$Qh1wj&{i+pDC=817;!TNjWDVK9rrV
z?DFfgkG_&~Ej>GP;EzhfxMba`Hv8#1w0!p0#hKI6RTRKQK9C2*#X6`R#&oE4IENE*
zjS;-P)tLY6J-)Q&{u1Ntcdjqyu5e^lSViOGitRl2NyZY<Zz*4>-QXb#MF+@TEkL(g
zjY<|$u~tvPy8FAO`*FFOrC;Fo<o=@<f1?q1H~q${WWHnbE$;q(tXqwaZ5%nuz4%l&
zkvo`tYZtcM182RZ`*nx<xFdD{eyf|4-n{e`JK~Voyw-aXZ)kpJgZ+DXhL7Cnow$Fw
z=^Ksmy9qo@m+DgK2;76Y$G(d@{5NUKR`J;Q=}62(_K?2BEEPNG<(3}{x&6S0X}l4+
zhe0FU7k-Q}cYe8lI13DPJx5_Ddwa9uEv))2$7~WEES!iBTcxw2dmGR390wNW3W9F>
zJ@~r}?8n-Pbr>dVa!2IMaW0)pqkHm~%4g~oXKW(r>)5@n!*zdD?9<Qj2E-c$+%!vw
z%sD8zG0^|K_H}20xBIQoiKj0jNAepxSwl_wsFO!m#VzHVocj7v_W<>sJH4w>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.<BR>
+
+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 <IndustryStandard/Mbr.h>
+#include <IndustryStandard/ElTorito.h>
+#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.<BR>
+#
+#  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.<BR>
+#
+#  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(<ezlz+bM`|b0v
zXKW~H)vB`2ce}Sc^XAR$?CkyV`+8bWm98)KtI|*DB#qKpdY?W|pQ)F3yXia~r>ops
z>FqdO<ma(QP0}nK>KbXxBwcFsiJqpqZ>2^W<hJEidV8a5rdi|ktTy7C^ir+;)Y6<C
zJ#A|KD1Fj6<Qz)wacy*0;}}&(6<Fh5w0AXsm_F+Nbit<Okw#J19b@8NrKW7VkQLxN
zO&?@Sm7Yre7rMVpU+MRqo}SNJU#D-gojaMO_u|YFrjh|ig|`=a)6jcH6xpyj73#~(
z1biH)7wLzzk$UOJTmKYvy*y%+IY!End={Q5JYHpa_;DinmqKzSEkn&MV~+CML-pUN
z*B%{fEMB|TyP0gS=6;Sga%Q)vD*2eG8Rd8y)@(%vlF@ge|EWeIk+{Im7wS2e_eW~E
z2W@aw>H3i8fe5zFGn$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-IS<B4TGt427#<~Zc^>Cj
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<SmEzvVU)6lGjA_b37NrC5|
z$B<VQ{=-(hV)h*^ef4ihA3h%FnFy?eVNbu!jKj#m+{<gTsi%JWUZdI?6KjLW+gGc#
zzz#OS8N67I(Kz-j#r>>|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^<UHwSmqgrSx;D7KN*`FpLfhA-a*4qbFG!?iVBW1Er^dY
z7WxW;R{AZ+2&Zz+g60*5iJGX29664q6G?Ps{!|f7#$uH{bl#_WoG$36rsE{U$pTBK
zHALndl<XNk>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{<qLT{VlD1}0v+}6&j0`b

literal 0
HcmV?d00001

diff --git a/FatPkg/FatPkgExtra.uni b/FatPkg/FatPkgExtra.uni
new file mode 100644
index 0000000000000000000000000000000000000000..b441ef8fa9765ada2900eff977a0f37a19367064
GIT binary patch
literal 4248
zcmd6rTW=#p5QY00iT^MPF99tHux|@OIJQF~96NZN4g0imu2}2Dk?jz|j|a|I$L+Qg
zXF=ixMV^_isjfP8?V9}c=Wg0fm4097uS!3pt29dEbeTR)pNPu4{WMH--H&xYPakx>
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<sqCbjy6=-k7i!~2=H<z_l
zP|F%Q^ChY(-RS*=c!>@^&$c21$>_V&bt+CI;%WSTC(1<Dj<hlbZH^~T>;n<rngkjm
zS4ju)LSxqCXriga>_)43db6aIHy`sJk|xsn)L-ZXCD!6sat?iS;U%LgJsI&Zor#wi
z8tHo86co4O0zdJ<Q|u?Am8^ASGm@9=b@pbxn>>Y&X3{VYlz3#CHs$v}dBhfO&XuPg
zaa1qlC1+a3_kZ_`>!idd<GxUw&SeeWqf3<h&Q-K4j;Z2CJjnr`Z-S5Kk)Fm8*XQ|O
zD$F~Jc1P}cb#IDZS2|s()}4{xN;9Z)9<6pKvJae3c}xByk(IM=6$v|egN={N`l^)o
z=yKPgzUR_WiAJ7!kFlWFzMyl^4f5JqW4%-x-g7sk6VNSgLT;`UdfJsFJP65p^=Hqz
zS5eJ$pmWJ{m$F8BGH4z`lRFc&T)NdvJ9FpG(aHBJ4bp*neytsK>gg;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?8<iThraI8zWwk}
z!PJnfW69_X#i8V#NCqpYC%PYtzt(O%=O|)n9acB=1df(EC_d}zip_ZSt$sv?JOE=y
zf5p=0F)oOD${6s1!O?gr%6J-N_!av*v9g7ZG!X_b$eTigx52rI*3=s^64c;*wGz2n
zen0|xc;mcjFR}#BybJ0oUcC0Rd}xW@37Up>HIyl2T$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<P3*9N4sQ^YYMI8fW46Oq|^zB
zPo<|Vy<A=U$SXP5SY{6XqtlQ{CF|Cu*-rPN)!N?_XR4*GD1eK6pqCIA%b<4{)2ZI$
zb9_Rsv2wS`RhPRNeaiL{<7{{CFZNyWk-frOBtGxh&U05XnuvZw`9kjo4^b#GK<;h<
zy7g{UvXG9oUIm-Z?}pCD)oGS_fzy-ok6HYUR-E0;8|$3;jLoOG=l5%!YD{d`k)xc8
zFHIA9g2|_L@s?-cEVoR*o=~4pq@LgJb#gMBm$_nJJ|s4;^_|4mn!n%h{-Z3zMo#or
zoWGp(Q?2s134R!_^rbQpcn0%~{SasP2T99XvDo;TNbHGhA#;hnRP-R1Q~p}WZ3i}t
z<BP~M3=;8u@sBa)$uG|jmw|z)XBc|2wX-#A@v6Ua>`kJBhI9GDTA8ev-uRXU@mXMj
zRuHt)@8Q4Oz<#EkXvf23O`eFHInJdkN%Ty<t$e0mQDY-<-^K1t6Rzi@qMvz=FCe}s
z@Xd4uk$nzIP7LIKT>7S3;7fluWMb)Okt6w=ovfiJy;tQiRdGuBB&WYZrF;FPEB)oY
nIt-@|m1<dFrYi0ip7m_{Wpr8dYzeg^bEkXxf5O%h5t9A}VU>=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

