]> git.proxmox.com Git - mirror_edk2.git/blobdiff - FatPkg/FatPei/FatLiteLib.c
FatPkg: Add FAT PEIM
[mirror_edk2.git] / FatPkg / FatPei / FatLiteLib.c
diff --git a/FatPkg/FatPei/FatLiteLib.c b/FatPkg/FatPei/FatLiteLib.c
new file mode 100644 (file)
index 0000000..b5191b6
--- /dev/null
@@ -0,0 +1,364 @@
+/** @file\r
+  General purpose supporting routines for FAT recovery PEIM\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "FatLitePeim.h"\r
+\r
+\r
+#define CHAR_FAT_VALID  0x01\r
+\r
+\r
+/**\r
+  Converts a union code character to upper case.\r
+  This functions converts a unicode character to upper case.\r
+  If the input Letter is not a lower-cased letter,\r
+  the original value is returned.\r
+\r
+  @param  Letter            The input unicode character. \r
+\r
+  @return The upper cased letter.\r
+\r
+**/\r
+CHAR16\r
+ToUpper (\r
+  IN CHAR16                    Letter\r
+  )\r
+{\r
+  if ('a' <= Letter && Letter <= 'z') {\r
+    Letter = (CHAR16) (Letter - 0x20);\r
+  }\r
+\r
+  return Letter;\r
+}\r
+\r
+\r
+/**\r
+  Reads a block of data from the block device by calling\r
+  underlying Block I/O service.\r
+\r
+  @param  PrivateData       Global memory map for accessing global variables \r
+  @param  BlockDeviceNo     The index for the block device number. \r
+  @param  Lba               The logic block address to read data from. \r
+  @param  BufferSize        The size of data in byte to read. \r
+  @param  Buffer            The buffer of the \r
+\r
+  @retval EFI_DEVICE_ERROR  The specified block device number exceeds the maximum \r
+                            device number. \r
+  @retval EFI_DEVICE_ERROR  The maximum address has exceeded the maximum address \r
+                            of the block device.\r
+\r
+**/\r
+EFI_STATUS\r
+FatReadBlock (\r
+  IN  PEI_FAT_PRIVATE_DATA   *PrivateData,\r
+  IN  UINTN                  BlockDeviceNo,\r
+  IN  EFI_PEI_LBA            Lba,\r
+  IN  UINTN                  BufferSize,\r
+  OUT VOID                   *Buffer\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  PEI_FAT_BLOCK_DEVICE  *BlockDev;\r
+\r
+  if (BlockDeviceNo > PEI_FAT_MAX_BLOCK_DEVICE - 1) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Status    = EFI_SUCCESS;\r
+  BlockDev  = &(PrivateData->BlockDevice[BlockDeviceNo]);\r
+\r
+  if (BufferSize > MultU64x32 (BlockDev->LastBlock - Lba + 1, BlockDev->BlockSize)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  if (!BlockDev->Logical) {\r
+    //\r
+    // Status = BlockDev->ReadFunc\r
+    //  (PrivateData->PeiServices, BlockDev->PhysicalDevNo, Lba, BufferSize, Buffer);\r
+    //\r
+    Status = BlockDev->BlockIo->ReadBlocks (\r
+                                  (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),\r
+                                  BlockDev->BlockIo,\r
+                                  BlockDev->PhysicalDevNo,\r
+                                  Lba,\r
+                                  BufferSize,\r
+                                  Buffer\r
+                                  );\r
+\r
+  } else {\r
+    Status = FatReadDisk (\r
+              PrivateData,\r
+              BlockDev->ParentDevNo,\r
+              BlockDev->StartingPos + MultU64x32 (Lba, BlockDev->BlockSize),\r
+              BufferSize,\r
+              Buffer\r
+              );\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Find a cache block designated to specific Block device and Lba.\r
+  If not found, invalidate an oldest one and use it. (LRU cache)\r
+\r
+  @param  PrivateData       the global memory map. \r
+  @param  BlockDeviceNo     the Block device. \r
+  @param  Lba               the Logical Block Address \r
+  @param  CachePtr          Ptr to the starting address of the memory holding the \r
+                            data; \r
+\r
+  @retval EFI_SUCCESS       The function completed successfully.\r
+  @retval EFI_DEVICE_ERROR  Something error while accessing media.\r
+\r
+**/\r
+EFI_STATUS\r
+FatGetCacheBlock (\r
+  IN  PEI_FAT_PRIVATE_DATA  *PrivateData,\r
+  IN  UINTN                 BlockDeviceNo,\r
+  IN  UINT64                Lba,\r
+  OUT CHAR8                 **CachePtr\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  PEI_FAT_CACHE_BUFFER  *CacheBuffer;\r
+  INTN                  Index;\r
+  STATIC UINT8          Seed;\r
+\r
+  Status      = EFI_SUCCESS;\r
+  CacheBuffer = NULL;\r
+\r
+  //\r
+  // go through existing cache buffers\r
+  //\r
+  for (Index = 0; Index < PEI_FAT_CACHE_SIZE; Index++) {\r
+    CacheBuffer = &(PrivateData->CacheBuffer[Index]);\r
+    if (CacheBuffer->Valid && CacheBuffer->BlockDeviceNo == BlockDeviceNo && CacheBuffer->Lba == Lba) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Index < PEI_FAT_CACHE_SIZE) {\r
+    *CachePtr = (CHAR8 *) CacheBuffer->Buffer;\r
+    return EFI_SUCCESS;\r
+  }\r
+  //\r
+  // We have to find an invalid cache buffer\r
+  //\r
+  for (Index = 0; Index < PEI_FAT_CACHE_SIZE; Index++) {\r
+    if (!PrivateData->CacheBuffer[Index].Valid) {\r
+      break;\r
+    }\r
+  }\r
+  //\r
+  // Use the cache buffer\r
+  //\r
+  if (Index == PEI_FAT_CACHE_SIZE) {\r
+    Index = (Seed++) % PEI_FAT_CACHE_SIZE;\r
+  }\r
+  \r
+  //\r
+  // Current device ID should be less than maximum device ID. \r
+  //\r
+  if (BlockDeviceNo >= PEI_FAT_MAX_BLOCK_DEVICE) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  CacheBuffer                 = &(PrivateData->CacheBuffer[Index]);\r
+\r
+  CacheBuffer->BlockDeviceNo  = BlockDeviceNo;\r
+  CacheBuffer->Lba            = Lba;\r
+  CacheBuffer->Size           = PrivateData->BlockDevice[BlockDeviceNo].BlockSize;\r
+\r
+  //\r
+  // Read in the data\r
+  //\r
+  Status = FatReadBlock (\r
+            PrivateData,\r
+            BlockDeviceNo,\r
+            Lba,\r
+            CacheBuffer->Size,\r
+            CacheBuffer->Buffer\r
+            );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  CacheBuffer->Valid  = TRUE;\r
+  *CachePtr           = (CHAR8 *) CacheBuffer->Buffer;\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Disk reading.\r
+\r
+  @param  PrivateData       the global memory map; \r
+  @param  BlockDeviceNo     the block device to read; \r
+  @param  StartingAddress   the starting address. \r
+  @param  Size              the amount of data to read. \r
+  @param  Buffer            the buffer holding the data \r
+\r
+  @retval EFI_SUCCESS       The function completed successfully.\r
+  @retval EFI_DEVICE_ERROR  Something error.\r
+\r
+**/\r
+EFI_STATUS\r
+FatReadDisk (\r
+  IN  PEI_FAT_PRIVATE_DATA  *PrivateData,\r
+  IN  UINTN                 BlockDeviceNo,\r
+  IN  UINT64                StartingAddress,\r
+  IN  UINTN                 Size,\r
+  OUT VOID                  *Buffer\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT32      BlockSize;\r
+  CHAR8       *BufferPtr;\r
+  CHAR8       *CachePtr;\r
+  UINT32      Offset;\r
+  UINT64      Lba;\r
+  UINT64      OverRunLba;\r
+  UINTN       Amount;\r
+\r
+  Status    = EFI_SUCCESS;\r
+  BufferPtr = Buffer;\r
+  BlockSize = PrivateData->BlockDevice[BlockDeviceNo].BlockSize;\r
+\r
+  //\r
+  // Read underrun\r
+  //\r
+  Lba     = DivU64x32Remainder (StartingAddress, BlockSize, &Offset);\r
+  Status  = FatGetCacheBlock (PrivateData, BlockDeviceNo, Lba, &CachePtr);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Amount = Size < (BlockSize - Offset) ? Size : (BlockSize - Offset);\r
+  CopyMem (BufferPtr, CachePtr + Offset, Amount);\r
+\r
+  if (Size == Amount) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Size -= Amount;\r
+  BufferPtr += Amount;\r
+  StartingAddress += Amount;\r
+  Lba += 1;\r
+\r
+  //\r
+  // Read aligned parts\r
+  //\r
+  OverRunLba = Lba + DivU64x32Remainder (Size, BlockSize, &Offset);\r
+\r
+  Size -= Offset;\r
+  Status = FatReadBlock (PrivateData, BlockDeviceNo, Lba, Size, BufferPtr);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  BufferPtr += Size;\r
+\r
+  //\r
+  // Read overrun\r
+  //\r
+  if (Offset != 0) {\r
+    Status = FatGetCacheBlock (PrivateData, BlockDeviceNo, OverRunLba, &CachePtr);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    CopyMem (BufferPtr, CachePtr, Offset);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This version is different from the version in Unicode collation\r
+  protocol in that this version strips off trailing blanks.\r
+  Converts an 8.3 FAT file name using an OEM character set\r
+  to a Null-terminated Unicode string.\r
+  Here does not expand DBCS FAT chars.\r
+\r
+  @param  FatSize           The size of the string Fat in bytes. \r
+  @param  Fat               A pointer to a Null-terminated string that contains \r
+                            an 8.3 file name using an OEM character set. \r
+  @param  Str               A pointer to a Null-terminated Unicode string. The \r
+                            string must be allocated in advance to hold FatSize \r
+                            Unicode characters\r
+\r
+**/\r
+VOID\r
+EngFatToStr (\r
+  IN UINTN                            FatSize,\r
+  IN CHAR8                            *Fat,\r
+  OUT CHAR16                          *Str\r
+  )\r
+{\r
+  CHAR16  *String;\r
+\r
+  String = Str;\r
+  //\r
+  // No DBCS issues, just expand and add null terminate to end of string\r
+  //\r
+  while (*Fat != 0 && FatSize != 0) {\r
+    *String = *Fat;\r
+    String += 1;\r
+    Fat += 1;\r
+    FatSize -= 1;\r
+    if (*Fat == ' ') {\r
+      *String = 0;\r
+      return ;\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Performs a case-insensitive comparison of two Null-terminated Unicode strings.\r
+\r
+  @param  PrivateData       Global memory map for accessing global variables \r
+  @param  Str1              First string to perform case insensitive comparison. \r
+  @param  Str2              Second string to perform case insensitive comparison.\r
+\r
+**/\r
+BOOLEAN\r
+EngStriColl (\r
+  IN  PEI_FAT_PRIVATE_DATA  *PrivateData,\r
+  IN CHAR16                 *Str1,\r
+  IN CHAR16                 *Str2\r
+  )\r
+{\r
+  CHAR16  UpperS1;\r
+  CHAR16  UpperS2;\r
+\r
+  UpperS1 = ToUpper (*Str1);\r
+  UpperS2 = ToUpper (*Str2);\r
+  while (*Str1 != 0) {\r
+    if (UpperS1 != UpperS2) {\r
+      return FALSE;\r
+    }\r
+\r
+    Str1++;\r
+    Str2++;\r
+    UpperS1 = ToUpper (*Str1);\r
+    UpperS2 = ToUpper (*Str2);\r
+  }\r
+\r
+  return (BOOLEAN) ((*Str2 != 0) ? FALSE : TRUE);\r
+}\r