Misc.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  1. /** @file
  2. Miscellaneous functions.
  3. Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include "Fat.h"
  7. UINT8 mMonthDays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  8. /**
  9. Create the task
  10. @param IFile - The instance of the open file.
  11. @param Token - A pointer to the token associated with the transaction.
  12. @return FAT_TASK * - Return the task instance.
  13. **/
  14. FAT_TASK *
  15. FatCreateTask (
  16. FAT_IFILE *IFile,
  17. EFI_FILE_IO_TOKEN *Token
  18. )
  19. {
  20. FAT_TASK *Task;
  21. Task = AllocateZeroPool (sizeof (*Task));
  22. if (Task != NULL) {
  23. Task->Signature = FAT_TASK_SIGNATURE;
  24. Task->IFile = IFile;
  25. Task->FileIoToken = Token;
  26. InitializeListHead (&Task->Subtasks);
  27. InitializeListHead (&Task->Link);
  28. }
  29. return Task;
  30. }
  31. /**
  32. Destroy the task.
  33. @param Task - The task to be destroyed.
  34. **/
  35. VOID
  36. FatDestroyTask (
  37. FAT_TASK *Task
  38. )
  39. {
  40. LIST_ENTRY *Link;
  41. FAT_SUBTASK *Subtask;
  42. Link = GetFirstNode (&Task->Subtasks);
  43. while (!IsNull (&Task->Subtasks, Link)) {
  44. Subtask = CR (Link, FAT_SUBTASK, Link, FAT_SUBTASK_SIGNATURE);
  45. Link = FatDestroySubtask (Subtask);
  46. }
  47. FreePool (Task);
  48. }
  49. /**
  50. Wait all non-blocking requests complete.
  51. @param IFile - The instance of the open file.
  52. **/
  53. VOID
  54. FatWaitNonblockingTask (
  55. FAT_IFILE *IFile
  56. )
  57. {
  58. BOOLEAN TaskQueueEmpty;
  59. do {
  60. EfiAcquireLock (&FatTaskLock);
  61. TaskQueueEmpty = IsListEmpty (&IFile->Tasks);
  62. EfiReleaseLock (&FatTaskLock);
  63. } while (!TaskQueueEmpty);
  64. }
  65. /**
  66. Remove the subtask from subtask list.
  67. @param Subtask - The subtask to be removed.
  68. @return LIST_ENTRY * - The next node in the list.
  69. **/
  70. LIST_ENTRY *
  71. FatDestroySubtask (
  72. FAT_SUBTASK *Subtask
  73. )
  74. {
  75. LIST_ENTRY *Link;
  76. gBS->CloseEvent (Subtask->DiskIo2Token.Event);
  77. Link = RemoveEntryList (&Subtask->Link);
  78. FreePool (Subtask);
  79. return Link;
  80. }
  81. /**
  82. Execute the task.
  83. @param IFile - The instance of the open file.
  84. @param Task - The task to be executed.
  85. @retval EFI_SUCCESS - The task was executed successfully.
  86. @return other - An error occurred when executing the task.
  87. **/
  88. EFI_STATUS
  89. FatQueueTask (
  90. IN FAT_IFILE *IFile,
  91. IN FAT_TASK *Task
  92. )
  93. {
  94. EFI_STATUS Status;
  95. LIST_ENTRY *Link;
  96. LIST_ENTRY *NextLink;
  97. FAT_SUBTASK *Subtask;
  98. //
  99. // Sometimes the Task doesn't contain any subtasks, signal the event directly.
  100. //
  101. if (IsListEmpty (&Task->Subtasks)) {
  102. Task->FileIoToken->Status = EFI_SUCCESS;
  103. gBS->SignalEvent (Task->FileIoToken->Event);
  104. FreePool (Task);
  105. return EFI_SUCCESS;
  106. }
  107. EfiAcquireLock (&FatTaskLock);
  108. InsertTailList (&IFile->Tasks, &Task->Link);
  109. EfiReleaseLock (&FatTaskLock);
  110. Status = EFI_SUCCESS;
  111. //
  112. // Use NextLink to store the next link of the list, because Link might be remove from the
  113. // doubly-linked list and get freed in the end of current loop.
  114. //
  115. // Also, list operation APIs like IsNull() and GetNextNode() are avoided during the loop, since
  116. // they may check the validity of doubly-linked lists by traversing them. These APIs cannot
  117. // handle list elements being removed during the traverse.
  118. //
  119. for ( Link = GetFirstNode (&Task->Subtasks), NextLink = GetNextNode (&Task->Subtasks, Link)
  120. ; Link != &Task->Subtasks
  121. ; Link = NextLink, NextLink = Link->ForwardLink
  122. )
  123. {
  124. Subtask = CR (Link, FAT_SUBTASK, Link, FAT_SUBTASK_SIGNATURE);
  125. if (Subtask->Write) {
  126. Status = IFile->OFile->Volume->DiskIo2->WriteDiskEx (
  127. IFile->OFile->Volume->DiskIo2,
  128. IFile->OFile->Volume->MediaId,
  129. Subtask->Offset,
  130. &Subtask->DiskIo2Token,
  131. Subtask->BufferSize,
  132. Subtask->Buffer
  133. );
  134. } else {
  135. Status = IFile->OFile->Volume->DiskIo2->ReadDiskEx (
  136. IFile->OFile->Volume->DiskIo2,
  137. IFile->OFile->Volume->MediaId,
  138. Subtask->Offset,
  139. &Subtask->DiskIo2Token,
  140. Subtask->BufferSize,
  141. Subtask->Buffer
  142. );
  143. }
  144. if (EFI_ERROR (Status)) {
  145. break;
  146. }
  147. }
  148. if (EFI_ERROR (Status)) {
  149. EfiAcquireLock (&FatTaskLock);
  150. //
  151. // Remove all the remaining subtasks when failure.
  152. // We shouldn't remove all the tasks because the non-blocking requests have
  153. // been submitted and cannot be canceled.
  154. //
  155. while (!IsNull (&Task->Subtasks, Link)) {
  156. Subtask = CR (Link, FAT_SUBTASK, Link, FAT_SUBTASK_SIGNATURE);
  157. Link = FatDestroySubtask (Subtask);
  158. }
  159. if (IsListEmpty (&Task->Subtasks)) {
  160. RemoveEntryList (&Task->Link);
  161. FreePool (Task);
  162. } else {
  163. //
  164. // If one or more subtasks have been already submitted, set FileIoToken
  165. // to NULL so that the callback won't signal the event.
  166. //
  167. Task->FileIoToken = NULL;
  168. }
  169. EfiReleaseLock (&FatTaskLock);
  170. }
  171. return Status;
  172. }
  173. /**
  174. Set the volume as dirty or not.
  175. @param Volume - FAT file system volume.
  176. @param IoMode - The access mode.
  177. @param DirtyValue - Set the volume as dirty or not.
  178. @retval EFI_SUCCESS - Set the new FAT entry value successfully.
  179. @return other - An error occurred when operation the FAT entries.
  180. **/
  181. EFI_STATUS
  182. FatAccessVolumeDirty (
  183. IN FAT_VOLUME *Volume,
  184. IN IO_MODE IoMode,
  185. IN VOID *DirtyValue
  186. )
  187. {
  188. UINTN WriteCount;
  189. WriteCount = Volume->FatEntrySize;
  190. return FatDiskIo (Volume, IoMode, Volume->FatPos + WriteCount, WriteCount, DirtyValue, NULL);
  191. }
  192. /**
  193. Invoke a notification event.
  194. @param Event Event whose notification function is being invoked.
  195. @param Context The pointer to the notification function's context,
  196. which is implementation-dependent.
  197. **/
  198. VOID
  199. EFIAPI
  200. FatOnAccessComplete (
  201. IN EFI_EVENT Event,
  202. IN VOID *Context
  203. )
  204. {
  205. EFI_STATUS Status;
  206. FAT_SUBTASK *Subtask;
  207. FAT_TASK *Task;
  208. //
  209. // Avoid someone in future breaks the below assumption.
  210. //
  211. ASSERT (EfiGetCurrentTpl () == FatTaskLock.Tpl);
  212. Subtask = (FAT_SUBTASK *)Context;
  213. Task = Subtask->Task;
  214. Status = Subtask->DiskIo2Token.TransactionStatus;
  215. ASSERT (Task->Signature == FAT_TASK_SIGNATURE);
  216. ASSERT (Subtask->Signature == FAT_SUBTASK_SIGNATURE);
  217. //
  218. // Remove the task unconditionally
  219. //
  220. FatDestroySubtask (Subtask);
  221. //
  222. // Task->FileIoToken is NULL which means the task will be ignored (just recycle the subtask and task memory).
  223. //
  224. if (Task->FileIoToken != NULL) {
  225. if (IsListEmpty (&Task->Subtasks) || EFI_ERROR (Status)) {
  226. Task->FileIoToken->Status = Status;
  227. gBS->SignalEvent (Task->FileIoToken->Event);
  228. //
  229. // Mark Task->FileIoToken to NULL so that the subtasks belonging to the task will be ignored.
  230. //
  231. Task->FileIoToken = NULL;
  232. }
  233. }
  234. if (IsListEmpty (&Task->Subtasks)) {
  235. RemoveEntryList (&Task->Link);
  236. FreePool (Task);
  237. }
  238. }
  239. /**
  240. General disk access function.
  241. @param Volume - FAT file system volume.
  242. @param IoMode - The access mode (disk read/write or cache access).
  243. @param Offset - The starting byte offset to read from.
  244. @param BufferSize - Size of Buffer.
  245. @param Buffer - Buffer containing read data.
  246. @param Task point to task instance.
  247. @retval EFI_SUCCESS - The operation is performed successfully.
  248. @retval EFI_VOLUME_CORRUPTED - The access is
  249. @return Others - The status of read/write the disk
  250. **/
  251. EFI_STATUS
  252. FatDiskIo (
  253. IN FAT_VOLUME *Volume,
  254. IN IO_MODE IoMode,
  255. IN UINT64 Offset,
  256. IN UINTN BufferSize,
  257. IN OUT VOID *Buffer,
  258. IN FAT_TASK *Task
  259. )
  260. {
  261. EFI_STATUS Status;
  262. EFI_DISK_IO_PROTOCOL *DiskIo;
  263. EFI_DISK_READ IoFunction;
  264. FAT_SUBTASK *Subtask;
  265. //
  266. // Verify the IO is in devices range
  267. //
  268. Status = EFI_VOLUME_CORRUPTED;
  269. if (Offset + BufferSize <= Volume->VolumeSize) {
  270. if (CACHE_ENABLED (IoMode)) {
  271. //
  272. // Access cache
  273. //
  274. Status = FatAccessCache (Volume, CACHE_TYPE (IoMode), RAW_ACCESS (IoMode), Offset, BufferSize, Buffer, Task);
  275. } else {
  276. //
  277. // Access disk directly
  278. //
  279. if (Task == NULL) {
  280. //
  281. // Blocking access
  282. //
  283. DiskIo = Volume->DiskIo;
  284. IoFunction = (IoMode == ReadDisk) ? DiskIo->ReadDisk : DiskIo->WriteDisk;
  285. Status = IoFunction (DiskIo, Volume->MediaId, Offset, BufferSize, Buffer);
  286. } else {
  287. //
  288. // Non-blocking access
  289. //
  290. Subtask = AllocateZeroPool (sizeof (*Subtask));
  291. if (Subtask == NULL) {
  292. Status = EFI_OUT_OF_RESOURCES;
  293. } else {
  294. Subtask->Signature = FAT_SUBTASK_SIGNATURE;
  295. Subtask->Task = Task;
  296. Subtask->Write = (BOOLEAN)(IoMode == WriteDisk);
  297. Subtask->Offset = Offset;
  298. Subtask->Buffer = Buffer;
  299. Subtask->BufferSize = BufferSize;
  300. Status = gBS->CreateEvent (
  301. EVT_NOTIFY_SIGNAL,
  302. TPL_NOTIFY,
  303. FatOnAccessComplete,
  304. Subtask,
  305. &Subtask->DiskIo2Token.Event
  306. );
  307. if (!EFI_ERROR (Status)) {
  308. InsertTailList (&Task->Subtasks, &Subtask->Link);
  309. } else {
  310. FreePool (Subtask);
  311. }
  312. }
  313. }
  314. }
  315. }
  316. if (EFI_ERROR (Status)) {
  317. Volume->DiskError = TRUE;
  318. DEBUG ((DEBUG_ERROR, "FatDiskIo: error %r\n", Status));
  319. }
  320. return Status;
  321. }
  322. /**
  323. Lock the volume.
  324. **/
  325. VOID
  326. FatAcquireLock (
  327. VOID
  328. )
  329. {
  330. EfiAcquireLock (&FatFsLock);
  331. }
  332. /**
  333. Lock the volume.
  334. If the lock is already in the acquired state, then EFI_ACCESS_DENIED is returned.
  335. Otherwise, EFI_SUCCESS is returned.
  336. @retval EFI_SUCCESS - The volume is locked.
  337. @retval EFI_ACCESS_DENIED - The volume could not be locked because it is already locked.
  338. **/
  339. EFI_STATUS
  340. FatAcquireLockOrFail (
  341. VOID
  342. )
  343. {
  344. return EfiAcquireLockOrFail (&FatFsLock);
  345. }
  346. /**
  347. Unlock the volume.
  348. **/
  349. VOID
  350. FatReleaseLock (
  351. VOID
  352. )
  353. {
  354. EfiReleaseLock (&FatFsLock);
  355. }
  356. /**
  357. Free directory entry.
  358. @param DirEnt - The directory entry to be freed.
  359. **/
  360. VOID
  361. FatFreeDirEnt (
  362. IN FAT_DIRENT *DirEnt
  363. )
  364. {
  365. if (DirEnt->FileString != NULL) {
  366. FreePool (DirEnt->FileString);
  367. }
  368. FreePool (DirEnt);
  369. }
  370. /**
  371. Free volume structure (including the contents of directory cache and disk cache).
  372. @param Volume - The volume structure to be freed.
  373. **/
  374. VOID
  375. FatFreeVolume (
  376. IN FAT_VOLUME *Volume
  377. )
  378. {
  379. //
  380. // Free disk cache
  381. //
  382. if (Volume->CacheBuffer != NULL) {
  383. FreePool (Volume->CacheBuffer);
  384. }
  385. //
  386. // Free directory cache
  387. //
  388. FatCleanupODirCache (Volume);
  389. FreePool (Volume);
  390. }
  391. /**
  392. Translate EFI time to FAT time.
  393. @param ETime - The time of EFI_TIME.
  394. @param FTime - The time of FAT_DATE_TIME.
  395. **/
  396. VOID
  397. FatEfiTimeToFatTime (
  398. IN EFI_TIME *ETime,
  399. OUT FAT_DATE_TIME *FTime
  400. )
  401. {
  402. //
  403. // ignores timezone info in source ETime
  404. //
  405. if (ETime->Year > 1980) {
  406. FTime->Date.Year = (UINT16)(ETime->Year - 1980);
  407. }
  408. if (ETime->Year >= 1980 + FAT_MAX_YEAR_FROM_1980) {
  409. FTime->Date.Year = FAT_MAX_YEAR_FROM_1980;
  410. }
  411. FTime->Date.Month = ETime->Month;
  412. FTime->Date.Day = ETime->Day;
  413. FTime->Time.Hour = ETime->Hour;
  414. FTime->Time.Minute = ETime->Minute;
  415. FTime->Time.DoubleSecond = (UINT16)(ETime->Second / 2);
  416. }
  417. /**
  418. Translate Fat time to EFI time.
  419. @param FTime - The time of FAT_DATE_TIME.
  420. @param ETime - The time of EFI_TIME..
  421. **/
  422. VOID
  423. FatFatTimeToEfiTime (
  424. IN FAT_DATE_TIME *FTime,
  425. OUT EFI_TIME *ETime
  426. )
  427. {
  428. ETime->Year = (UINT16)(FTime->Date.Year + 1980);
  429. ETime->Month = (UINT8)FTime->Date.Month;
  430. ETime->Day = (UINT8)FTime->Date.Day;
  431. ETime->Hour = (UINT8)FTime->Time.Hour;
  432. ETime->Minute = (UINT8)FTime->Time.Minute;
  433. ETime->Second = (UINT8)(FTime->Time.DoubleSecond * 2);
  434. ETime->Nanosecond = 0;
  435. ETime->TimeZone = EFI_UNSPECIFIED_TIMEZONE;
  436. ETime->Daylight = 0;
  437. }
  438. /**
  439. Get Current FAT time.
  440. @param FatNow - Current FAT time.
  441. **/
  442. VOID
  443. FatGetCurrentFatTime (
  444. OUT FAT_DATE_TIME *FatNow
  445. )
  446. {
  447. EFI_STATUS Status;
  448. EFI_TIME Now;
  449. Status = gRT->GetTime (&Now, NULL);
  450. if (!EFI_ERROR (Status)) {
  451. FatEfiTimeToFatTime (&Now, FatNow);
  452. } else {
  453. ZeroMem (&Now, sizeof (EFI_TIME));
  454. Now.Year = 1980;
  455. Now.Month = 1;
  456. Now.Day = 1;
  457. FatEfiTimeToFatTime (&Now, FatNow);
  458. }
  459. }
  460. /**
  461. Check whether a time is valid.
  462. @param Time - The time of EFI_TIME.
  463. @retval TRUE - The time is valid.
  464. @retval FALSE - The time is not valid.
  465. **/
  466. BOOLEAN
  467. FatIsValidTime (
  468. IN EFI_TIME *Time
  469. )
  470. {
  471. UINTN Day;
  472. BOOLEAN ValidTime;
  473. ValidTime = TRUE;
  474. //
  475. // Check the fields for range problems
  476. // Fat can only support from 1980
  477. //
  478. if ((Time->Year < 1980) ||
  479. (Time->Month < 1) ||
  480. (Time->Month > 12) ||
  481. (Time->Day < 1) ||
  482. (Time->Day > 31) ||
  483. (Time->Hour > 23) ||
  484. (Time->Minute > 59) ||
  485. (Time->Second > 59) ||
  486. (Time->Nanosecond > 999999999)
  487. )
  488. {
  489. ValidTime = FALSE;
  490. } else {
  491. //
  492. // Perform a more specific check of the day of the month
  493. //
  494. Day = mMonthDays[Time->Month - 1];
  495. if ((Time->Month == 2) && IS_LEAP_YEAR (Time->Year)) {
  496. Day += 1;
  497. //
  498. // 1 extra day this month
  499. //
  500. }
  501. if (Time->Day > Day) {
  502. ValidTime = FALSE;
  503. }
  504. }
  505. return ValidTime;
  506. }