Home | History | Annotate | Download | only in FatPei
      1 /** @file
      2   General purpose supporting routines for FAT recovery PEIM
      3 
      4 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
      5 
      6 This program and the accompanying materials are licensed and made available
      7 under the terms and conditions of the BSD License which accompanies this
      8 distribution. The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "FatLitePeim.h"
     17 
     18 
     19 #define CHAR_FAT_VALID  0x01
     20 
     21 
     22 /**
     23   Converts a union code character to upper case.
     24   This functions converts a unicode character to upper case.
     25   If the input Letter is not a lower-cased letter,
     26   the original value is returned.
     27 
     28   @param  Letter            The input unicode character.
     29 
     30   @return The upper cased letter.
     31 
     32 **/
     33 CHAR16
     34 ToUpper (
     35   IN CHAR16                    Letter
     36   )
     37 {
     38   if ('a' <= Letter && Letter <= 'z') {
     39     Letter = (CHAR16) (Letter - 0x20);
     40   }
     41 
     42   return Letter;
     43 }
     44 
     45 
     46 /**
     47   Reads a block of data from the block device by calling
     48   underlying Block I/O service.
     49 
     50   @param  PrivateData       Global memory map for accessing global variables
     51   @param  BlockDeviceNo     The index for the block device number.
     52   @param  Lba               The logic block address to read data from.
     53   @param  BufferSize        The size of data in byte to read.
     54   @param  Buffer            The buffer of the
     55 
     56   @retval EFI_DEVICE_ERROR  The specified block device number exceeds the maximum
     57                             device number.
     58   @retval EFI_DEVICE_ERROR  The maximum address has exceeded the maximum address
     59                             of the block device.
     60 
     61 **/
     62 EFI_STATUS
     63 FatReadBlock (
     64   IN  PEI_FAT_PRIVATE_DATA   *PrivateData,
     65   IN  UINTN                  BlockDeviceNo,
     66   IN  EFI_PEI_LBA            Lba,
     67   IN  UINTN                  BufferSize,
     68   OUT VOID                   *Buffer
     69   )
     70 {
     71   EFI_STATUS            Status;
     72   PEI_FAT_BLOCK_DEVICE  *BlockDev;
     73 
     74   if (BlockDeviceNo > PEI_FAT_MAX_BLOCK_DEVICE - 1) {
     75     return EFI_DEVICE_ERROR;
     76   }
     77 
     78   Status    = EFI_SUCCESS;
     79   BlockDev  = &(PrivateData->BlockDevice[BlockDeviceNo]);
     80 
     81   if (BufferSize > MultU64x32 (BlockDev->LastBlock - Lba + 1, BlockDev->BlockSize)) {
     82     return EFI_DEVICE_ERROR;
     83   }
     84 
     85   if (!BlockDev->Logical) {
     86     //
     87     // Status = BlockDev->ReadFunc
     88     //  (PrivateData->PeiServices, BlockDev->PhysicalDevNo, Lba, BufferSize, Buffer);
     89     //
     90     if (BlockDev->BlockIo2 != NULL) {
     91       Status = BlockDev->BlockIo2->ReadBlocks (
     92                                     (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
     93                                     BlockDev->BlockIo2,
     94                                     BlockDev->PhysicalDevNo,
     95                                     Lba,
     96                                     BufferSize,
     97                                     Buffer
     98                                     );
     99     } else {
    100       Status = BlockDev->BlockIo->ReadBlocks (
    101                                   (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
    102                                   BlockDev->BlockIo,
    103                                   BlockDev->PhysicalDevNo,
    104                                   Lba,
    105                                   BufferSize,
    106                                   Buffer
    107                                   );
    108     }
    109 
    110   } else {
    111     Status = FatReadDisk (
    112               PrivateData,
    113               BlockDev->ParentDevNo,
    114               BlockDev->StartingPos + MultU64x32 (Lba, BlockDev->BlockSize),
    115               BufferSize,
    116               Buffer
    117               );
    118   }
    119 
    120   return Status;
    121 }
    122 
    123 
    124 /**
    125   Find a cache block designated to specific Block device and Lba.
    126   If not found, invalidate an oldest one and use it. (LRU cache)
    127 
    128   @param  PrivateData       the global memory map.
    129   @param  BlockDeviceNo     the Block device.
    130   @param  Lba               the Logical Block Address
    131   @param  CachePtr          Ptr to the starting address of the memory holding the
    132                             data;
    133 
    134   @retval EFI_SUCCESS       The function completed successfully.
    135   @retval EFI_DEVICE_ERROR  Something error while accessing media.
    136 
    137 **/
    138 EFI_STATUS
    139 FatGetCacheBlock (
    140   IN  PEI_FAT_PRIVATE_DATA  *PrivateData,
    141   IN  UINTN                 BlockDeviceNo,
    142   IN  UINT64                Lba,
    143   OUT CHAR8                 **CachePtr
    144   )
    145 {
    146   EFI_STATUS            Status;
    147   PEI_FAT_CACHE_BUFFER  *CacheBuffer;
    148   INTN                  Index;
    149   STATIC UINT8          Seed;
    150 
    151   Status      = EFI_SUCCESS;
    152   CacheBuffer = NULL;
    153 
    154   //
    155   // go through existing cache buffers
    156   //
    157   for (Index = 0; Index < PEI_FAT_CACHE_SIZE; Index++) {
    158     CacheBuffer = &(PrivateData->CacheBuffer[Index]);
    159     if (CacheBuffer->Valid && CacheBuffer->BlockDeviceNo == BlockDeviceNo && CacheBuffer->Lba == Lba) {
    160       break;
    161     }
    162   }
    163 
    164   if (Index < PEI_FAT_CACHE_SIZE) {
    165     *CachePtr = (CHAR8 *) CacheBuffer->Buffer;
    166     return EFI_SUCCESS;
    167   }
    168   //
    169   // We have to find an invalid cache buffer
    170   //
    171   for (Index = 0; Index < PEI_FAT_CACHE_SIZE; Index++) {
    172     if (!PrivateData->CacheBuffer[Index].Valid) {
    173       break;
    174     }
    175   }
    176   //
    177   // Use the cache buffer
    178   //
    179   if (Index == PEI_FAT_CACHE_SIZE) {
    180     Index = (Seed++) % PEI_FAT_CACHE_SIZE;
    181   }
    182 
    183   //
    184   // Current device ID should be less than maximum device ID.
    185   //
    186   if (BlockDeviceNo >= PEI_FAT_MAX_BLOCK_DEVICE) {
    187     return EFI_DEVICE_ERROR;
    188   }
    189 
    190   CacheBuffer                 = &(PrivateData->CacheBuffer[Index]);
    191 
    192   CacheBuffer->BlockDeviceNo  = BlockDeviceNo;
    193   CacheBuffer->Lba            = Lba;
    194   CacheBuffer->Size           = PrivateData->BlockDevice[BlockDeviceNo].BlockSize;
    195 
    196   //
    197   // Read in the data
    198   //
    199   Status = FatReadBlock (
    200             PrivateData,
    201             BlockDeviceNo,
    202             Lba,
    203             CacheBuffer->Size,
    204             CacheBuffer->Buffer
    205             );
    206   if (EFI_ERROR (Status)) {
    207     return EFI_DEVICE_ERROR;
    208   }
    209 
    210   CacheBuffer->Valid  = TRUE;
    211   *CachePtr           = (CHAR8 *) CacheBuffer->Buffer;
    212 
    213   return Status;
    214 }
    215 
    216 
    217 /**
    218   Disk reading.
    219 
    220   @param  PrivateData       the global memory map;
    221   @param  BlockDeviceNo     the block device to read;
    222   @param  StartingAddress   the starting address.
    223   @param  Size              the amount of data to read.
    224   @param  Buffer            the buffer holding the data
    225 
    226   @retval EFI_SUCCESS       The function completed successfully.
    227   @retval EFI_DEVICE_ERROR  Something error.
    228 
    229 **/
    230 EFI_STATUS
    231 FatReadDisk (
    232   IN  PEI_FAT_PRIVATE_DATA  *PrivateData,
    233   IN  UINTN                 BlockDeviceNo,
    234   IN  UINT64                StartingAddress,
    235   IN  UINTN                 Size,
    236   OUT VOID                  *Buffer
    237   )
    238 {
    239   EFI_STATUS  Status;
    240   UINT32      BlockSize;
    241   CHAR8       *BufferPtr;
    242   CHAR8       *CachePtr;
    243   UINT32      Offset;
    244   UINT64      Lba;
    245   UINT64      OverRunLba;
    246   UINTN       Amount;
    247 
    248   Status    = EFI_SUCCESS;
    249   BufferPtr = Buffer;
    250   BlockSize = PrivateData->BlockDevice[BlockDeviceNo].BlockSize;
    251 
    252   //
    253   // Read underrun
    254   //
    255   Lba     = DivU64x32Remainder (StartingAddress, BlockSize, &Offset);
    256   Status  = FatGetCacheBlock (PrivateData, BlockDeviceNo, Lba, &CachePtr);
    257   if (EFI_ERROR (Status)) {
    258     return EFI_DEVICE_ERROR;
    259   }
    260 
    261   Amount = Size < (BlockSize - Offset) ? Size : (BlockSize - Offset);
    262   CopyMem (BufferPtr, CachePtr + Offset, Amount);
    263 
    264   if (Size == Amount) {
    265     return EFI_SUCCESS;
    266   }
    267 
    268   Size -= Amount;
    269   BufferPtr += Amount;
    270   StartingAddress += Amount;
    271   Lba += 1;
    272 
    273   //
    274   // Read aligned parts
    275   //
    276   OverRunLba = Lba + DivU64x32Remainder (Size, BlockSize, &Offset);
    277 
    278   Size -= Offset;
    279   Status = FatReadBlock (PrivateData, BlockDeviceNo, Lba, Size, BufferPtr);
    280   if (EFI_ERROR (Status)) {
    281     return EFI_DEVICE_ERROR;
    282   }
    283 
    284   BufferPtr += Size;
    285 
    286   //
    287   // Read overrun
    288   //
    289   if (Offset != 0) {
    290     Status = FatGetCacheBlock (PrivateData, BlockDeviceNo, OverRunLba, &CachePtr);
    291     if (EFI_ERROR (Status)) {
    292       return EFI_DEVICE_ERROR;
    293     }
    294 
    295     CopyMem (BufferPtr, CachePtr, Offset);
    296   }
    297 
    298   return Status;
    299 }
    300 
    301 
    302 /**
    303   This version is different from the version in Unicode collation
    304   protocol in that this version strips off trailing blanks.
    305   Converts an 8.3 FAT file name using an OEM character set
    306   to a Null-terminated Unicode string.
    307   Here does not expand DBCS FAT chars.
    308 
    309   @param  FatSize           The size of the string Fat in bytes.
    310   @param  Fat               A pointer to a Null-terminated string that contains
    311                             an 8.3 file name using an OEM character set.
    312   @param  Str               A pointer to a Null-terminated Unicode string. The
    313                             string must be allocated in advance to hold FatSize
    314                             Unicode characters
    315 
    316 **/
    317 VOID
    318 EngFatToStr (
    319   IN UINTN                            FatSize,
    320   IN CHAR8                            *Fat,
    321   OUT CHAR16                          *Str
    322   )
    323 {
    324   CHAR16  *String;
    325 
    326   String = Str;
    327   //
    328   // No DBCS issues, just expand and add null terminate to end of string
    329   //
    330   while (*Fat != 0 && FatSize != 0) {
    331     if (*Fat == ' ') {
    332       break;
    333     }
    334     *String = *Fat;
    335     String += 1;
    336     Fat += 1;
    337     FatSize -= 1;
    338   }
    339 
    340   *String = 0;
    341 }
    342 
    343 
    344 /**
    345   Performs a case-insensitive comparison of two Null-terminated Unicode strings.
    346 
    347   @param  PrivateData       Global memory map for accessing global variables
    348   @param  Str1              First string to perform case insensitive comparison.
    349   @param  Str2              Second string to perform case insensitive comparison.
    350 
    351 **/
    352 BOOLEAN
    353 EngStriColl (
    354   IN  PEI_FAT_PRIVATE_DATA  *PrivateData,
    355   IN CHAR16                 *Str1,
    356   IN CHAR16                 *Str2
    357   )
    358 {
    359   CHAR16  UpperS1;
    360   CHAR16  UpperS2;
    361 
    362   UpperS1 = ToUpper (*Str1);
    363   UpperS2 = ToUpper (*Str2);
    364   while (*Str1 != 0) {
    365     if (UpperS1 != UpperS2) {
    366       return FALSE;
    367     }
    368 
    369     Str1++;
    370     Str2++;
    371     UpperS1 = ToUpper (*Str1);
    372     UpperS2 = ToUpper (*Str2);
    373   }
    374 
    375   return (BOOLEAN) ((*Str2 != 0) ? FALSE : TRUE);
    376 }
    377