FatLiteLib.c 9.8 KB

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