]> git.proxmox.com Git - mirror_edk2.git/blame - FatPkg/EnhancedFatDxe/Misc.c
Remove the RemoteEntryList() because the Task isn't added to the linked list upon...
[mirror_edk2.git] / FatPkg / EnhancedFatDxe / Misc.c
CommitLineData
b9ec9330
QH
1/*++\r
2\r
149d6335 3Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.<BR>\r
6163cc98 4This program and the accompanying materials are licensed and made available\r
b9ec9330
QH
5under the terms and conditions of the BSD License which accompanies this\r
6distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12\r
13Module Name:\r
14\r
15 Misc.c\r
16\r
17Abstract:\r
18\r
19 Miscellaneous functions\r
20\r
21Revision History\r
22\r
23--*/\r
24\r
25#include "Fat.h"\r
26\r
149d6335
RN
27FAT_TASK *\r
28FatCreateTask (\r
29 FAT_IFILE *IFile,\r
30 EFI_FILE_IO_TOKEN *Token\r
31 )\r
32/*++\r
33\r
34Routine Description:\r
35\r
36 Create the task\r
37\r
38Arguments:\r
39\r
40 IFile - The instance of the open file.\r
41 Token - A pointer to the token associated with the transaction.\r
42\r
43Return:\r
44 FAT_TASK * - Return the task instance.\r
45**/\r
46{\r
47 FAT_TASK *Task;\r
48\r
49 Task = AllocateZeroPool (sizeof (*Task));\r
50 if (Task != NULL) {\r
51 Task->Signature = FAT_TASK_SIGNATURE;\r
52 Task->IFile = IFile;\r
53 Task->FileIoToken = Token;\r
54 InitializeListHead (&Task->Subtasks);\r
55 InitializeListHead (&Task->Link);\r
56 }\r
57 return Task;\r
58}\r
59\r
60VOID\r
61FatDestroyTask (\r
62 FAT_TASK *Task\r
63 )\r
64/*++\r
65\r
66Routine Description:\r
67\r
68 Destroy the task\r
69\r
70Arguments:\r
71\r
72 Task - The task to be destroyed.\r
73**/\r
74{\r
75 LIST_ENTRY *Link;\r
76 FAT_SUBTASK *Subtask;\r
77\r
78 Link = GetFirstNode (&Task->Subtasks);\r
79 while (!IsNull (&Task->Subtasks, Link)) {\r
80 Subtask = CR (Link, FAT_SUBTASK, Link, FAT_SUBTASK_SIGNATURE);\r
81 Link = FatDestroySubtask (Subtask);\r
82 }\r
149d6335
RN
83 FreePool (Task);\r
84}\r
85\r
86VOID\r
87FatWaitNonblockingTask (\r
88 FAT_IFILE *IFile\r
89 )\r
90/*++\r
91\r
92Routine Description:\r
93\r
94 Wait all non-blocking requests complete.\r
95\r
96Arguments:\r
97\r
98 IFile - The instance of the open file.\r
99**/\r
100{\r
101 BOOLEAN TaskQueueEmpty;\r
102\r
103 do {\r
104 EfiAcquireLock (&FatTaskLock);\r
105 TaskQueueEmpty = IsListEmpty (&IFile->Tasks);\r
106 EfiReleaseLock (&FatTaskLock);\r
107 } while (!TaskQueueEmpty);\r
108}\r
109\r
110LIST_ENTRY *\r
111FatDestroySubtask (\r
112 FAT_SUBTASK *Subtask\r
113 )\r
114/*++\r
115\r
116Routine Description:\r
117\r
118 Remove the subtask from subtask list.\r
119\r
120Arguments:\r
121\r
122 Subtask - The subtask to be removed.\r
123\r
124Returns:\r
125\r
126 LIST_ENTRY * - The next node in the list.\r
127\r
128--*/\r
129{\r
130 LIST_ENTRY *Link;\r
131\r
132 gBS->CloseEvent (Subtask->DiskIo2Token.Event);\r
133\r
134 Link = RemoveEntryList (&Subtask->Link);\r
135 FreePool (Subtask);\r
136\r
137 return Link;\r
138}\r
139\r
140EFI_STATUS\r
141FatQueueTask (\r
142 IN FAT_IFILE *IFile,\r
143 IN FAT_TASK *Task\r
144 )\r
145/*++\r
146\r
147Routine Description:\r
148\r
149 Execute the task\r
150\r
151Arguments:\r
152\r
153 IFile - The instance of the open file.\r
154 Task - The task to be executed.\r
155\r
156Returns:\r
157\r
158 EFI_SUCCESS - The task was executed sucessfully.\r
159 other - An error occurred when executing the task.\r
160\r
161--*/\r
162{\r
163 EFI_STATUS Status;\r
164 LIST_ENTRY *Link;\r
165 FAT_SUBTASK *Subtask;\r
166\r
167 //\r
168 // Sometimes the Task doesn't contain any subtasks, signal the event directly.\r
169 //\r
170 if (IsListEmpty (&Task->Subtasks)) {\r
171 Task->FileIoToken->Status = EFI_SUCCESS;\r
172 gBS->SignalEvent (Task->FileIoToken->Event);\r
173 FreePool (Task);\r
174 return EFI_SUCCESS;\r
175 }\r
176\r
177 EfiAcquireLock (&FatTaskLock);\r
178 InsertTailList (&IFile->Tasks, &Task->Link);\r
179 EfiReleaseLock (&FatTaskLock);\r
180\r
181 Status = EFI_SUCCESS;\r
182 for ( Link = GetFirstNode (&Task->Subtasks)\r
183 ; !IsNull (&Task->Subtasks, Link)\r
184 ; Link = GetNextNode (&Task->Subtasks, Link)\r
185 ) {\r
186 Subtask = CR (Link, FAT_SUBTASK, Link, FAT_SUBTASK_SIGNATURE);\r
187 if (Subtask->Write) {\r
188 \r
189 Status = IFile->OFile->Volume->DiskIo2->WriteDiskEx (\r
190 IFile->OFile->Volume->DiskIo2,\r
191 IFile->OFile->Volume->MediaId,\r
192 Subtask->Offset,\r
193 &Subtask->DiskIo2Token,\r
194 Subtask->BufferSize,\r
195 Subtask->Buffer\r
196 );\r
197 } else {\r
198 Status = IFile->OFile->Volume->DiskIo2->ReadDiskEx (\r
199 IFile->OFile->Volume->DiskIo2,\r
200 IFile->OFile->Volume->MediaId,\r
201 Subtask->Offset,\r
202 &Subtask->DiskIo2Token,\r
203 Subtask->BufferSize,\r
204 Subtask->Buffer\r
205 );\r
206 }\r
207 if (EFI_ERROR (Status)) {\r
208 break;\r
209 }\r
210 }\r
211\r
212 if (EFI_ERROR (Status)) {\r
213 EfiAcquireLock (&FatTaskLock);\r
214 //\r
215 // Remove all the remaining subtasks when failure.\r
216 // We shouldn't remove all the tasks because the non-blocking requests have\r
217 // been submitted and cannot be canceled.\r
218 //\r
219 while (!IsNull (&Task->Subtasks, Link)) {\r
220 Subtask = CR (Link, FAT_SUBTASK, Link, FAT_SUBTASK_SIGNATURE);\r
221 Link = FatDestroySubtask (Subtask);\r
222 }\r
223\r
224 if (IsListEmpty (&Task->Subtasks)) {\r
225 RemoveEntryList (&Task->Link);\r
226 FreePool (Task);\r
227 } else {\r
228 //\r
229 // If one or more subtasks have been already submitted, set FileIoToken\r
230 // to NULL so that the callback won't signal the event.\r
231 //\r
232 Task->FileIoToken = NULL;\r
233 }\r
234\r
235 EfiReleaseLock (&FatTaskLock);\r
236 }\r
237\r
238 return Status;\r
239}\r
240\r
b9ec9330
QH
241EFI_STATUS\r
242FatAccessVolumeDirty (\r
243 IN FAT_VOLUME *Volume,\r
244 IN IO_MODE IoMode,\r
245 IN VOID *DirtyValue\r
246 )\r
247/*++\r
248\r
249Routine Description:\r
250\r
251 Set the volume as dirty or not\r
252\r
253Arguments:\r
254\r
255 Volume - FAT file system volume.\r
256 IoMode - The access mode.\r
257 DirtyValue - Set the volume as dirty or not.\r
258\r
259Returns:\r
260\r
261 EFI_SUCCESS - Set the new FAT entry value sucessfully.\r
262 other - An error occurred when operation the FAT entries.\r
263\r
264--*/\r
265{\r
266 UINTN WriteCount;\r
267\r
268 WriteCount = Volume->FatEntrySize;\r
149d6335
RN
269 return FatDiskIo (Volume, IoMode, Volume->FatPos + WriteCount, WriteCount, DirtyValue, NULL);\r
270}\r
271\r
272/**\r
273 Invoke a notification event\r
274\r
275 @param Event Event whose notification function is being invoked.\r
276 @param Context The pointer to the notification function's context,\r
277 which is implementation-dependent.\r
278\r
279**/\r
280VOID\r
281EFIAPI\r
282FatOnAccessComplete (\r
283 IN EFI_EVENT Event,\r
284 IN VOID *Context\r
285 )\r
286/*++\r
287\r
288Routine Description:\r
289\r
290 Invoke a notification event\r
291 case #1. some subtasks are not completed when the FatOpenEx checks the Task->Subtasks\r
292 - sets Task->SubtaskCollected so callback to signal the event and free the task.\r
293 case #2. all subtasks are completed when the FatOpenEx checks the Task->Subtasks\r
294 - FatOpenEx signal the event and free the task.\r
295Arguments:\r
296\r
297 Event - Event whose notification function is being invoked.\r
298 Context - The pointer to the notification function's context,\r
299 which is implementation-dependent.\r
300\r
301--*/\r
302{\r
303 EFI_STATUS Status;\r
304 FAT_SUBTASK *Subtask;\r
305 FAT_TASK *Task;\r
306\r
307 //\r
308 // Avoid someone in future breaks the below assumption.\r
309 //\r
310 ASSERT (EfiGetCurrentTpl () == FatTaskLock.Tpl);\r
311\r
312 Subtask = (FAT_SUBTASK *) Context;\r
313 Task = Subtask->Task;\r
314 Status = Subtask->DiskIo2Token.TransactionStatus;\r
315\r
316 ASSERT (Task->Signature == FAT_TASK_SIGNATURE);\r
317 ASSERT (Subtask->Signature == FAT_SUBTASK_SIGNATURE);\r
318\r
319 //\r
320 // Remove the task unconditionally\r
321 //\r
322 FatDestroySubtask (Subtask);\r
323\r
324 //\r
325 // Task->FileIoToken is NULL which means the task will be ignored (just recycle the subtask and task memory).\r
326 //\r
327 if (Task->FileIoToken != NULL) {\r
328 if (IsListEmpty (&Task->Subtasks) || EFI_ERROR (Status)) {\r
329 Task->FileIoToken->Status = Status;\r
330 gBS->SignalEvent (Task->FileIoToken->Event);\r
331 //\r
332 // Mark Task->FileIoToken to NULL so that the subtasks belonging to the task will be ignored.\r
333 //\r
334 Task->FileIoToken = NULL;\r
335 }\r
336 }\r
337\r
338 if (IsListEmpty (&Task->Subtasks)) {\r
339 RemoveEntryList (&Task->Link);\r
340 FreePool (Task);\r
341 }\r
b9ec9330
QH
342}\r
343\r
344EFI_STATUS\r
345FatDiskIo (\r
346 IN FAT_VOLUME *Volume,\r
347 IN IO_MODE IoMode,\r
348 IN UINT64 Offset,\r
349 IN UINTN BufferSize,\r
149d6335
RN
350 IN OUT VOID *Buffer,\r
351 IN FAT_TASK *Task\r
b9ec9330
QH
352 )\r
353/*++\r
354\r
355Routine Description:\r
356\r
357 General disk access function\r
358\r
359Arguments:\r
360\r
361 Volume - FAT file system volume.\r
362 IoMode - The access mode (disk read/write or cache access).\r
363 Offset - The starting byte offset to read from.\r
364 BufferSize - Size of Buffer.\r
365 Buffer - Buffer containing read data.\r
366\r
367Returns:\r
368\r
369 EFI_SUCCESS - The operation is performed successfully.\r
370 EFI_VOLUME_CORRUPTED - The accesss is\r
371 Others - The status of read/write the disk\r
372\r
373--*/\r
374{\r
375 EFI_STATUS Status;\r
376 EFI_DISK_IO_PROTOCOL *DiskIo;\r
377 EFI_DISK_READ IoFunction;\r
149d6335 378 FAT_SUBTASK *Subtask;\r
b9ec9330
QH
379\r
380 //\r
381 // Verify the IO is in devices range\r
382 //\r
383 Status = EFI_VOLUME_CORRUPTED;\r
384 if (Offset + BufferSize <= Volume->VolumeSize) {\r
385 if (CACHE_ENABLED (IoMode)) {\r
386 //\r
387 // Access cache\r
388 //\r
149d6335 389 Status = FatAccessCache (Volume, CACHE_TYPE (IoMode), RAW_ACCESS (IoMode), Offset, BufferSize, Buffer, Task);\r
b9ec9330
QH
390 } else {\r
391 //\r
392 // Access disk directly\r
393 //\r
149d6335
RN
394 if (Task == NULL) {\r
395 //\r
396 // Blocking access\r
397 //\r
398 DiskIo = Volume->DiskIo;\r
399 IoFunction = (IoMode == READ_DISK) ? DiskIo->ReadDisk : DiskIo->WriteDisk;\r
400 Status = IoFunction (DiskIo, Volume->MediaId, Offset, BufferSize, Buffer);\r
401 } else {\r
402 //\r
403 // Non-blocking access\r
404 //\r
405 Subtask = AllocateZeroPool (sizeof (*Subtask));\r
406 if (Subtask == NULL) {\r
407 Status = EFI_OUT_OF_RESOURCES;\r
408 } else {\r
409 Subtask->Signature = FAT_SUBTASK_SIGNATURE;\r
410 Subtask->Task = Task;\r
411 Subtask->Write = (BOOLEAN) (IoMode == WRITE_DISK);\r
412 Subtask->Offset = Offset;\r
413 Subtask->Buffer = Buffer;\r
414 Subtask->BufferSize = BufferSize;\r
415 Status = gBS->CreateEvent (\r
416 EVT_NOTIFY_SIGNAL,\r
417 TPL_NOTIFY,\r
418 FatOnAccessComplete,\r
419 Subtask,\r
420 &Subtask->DiskIo2Token.Event\r
421 );\r
422 if (!EFI_ERROR (Status)) {\r
423 InsertTailList (&Task->Subtasks, &Subtask->Link);\r
424 } else {\r
425 FreePool (Subtask);\r
426 }\r
427 }\r
428 }\r
b9ec9330
QH
429 }\r
430 }\r
431\r
432 if (EFI_ERROR (Status)) {\r
433 Volume->DiskError = TRUE;\r
149d6335 434 DEBUG ((EFI_D_ERROR, "FatDiskIo: error %r\n", Status));\r
b9ec9330
QH
435 }\r
436\r
437 return Status;\r
438}\r
439\r
440VOID\r
441FatAcquireLock (\r
442 VOID\r
443 )\r
444/*++\r
445\r
446Routine Description:\r
447\r
448 Lock the volume.\r
449\r
450Arguments:\r
451\r
452 None.\r
453\r
454Returns:\r
455\r
456 None.\r
457\r
458--*/\r
459{\r
460 EfiAcquireLock (&FatFsLock);\r
461}\r
462\r
25ce9b1f
QH
463EFI_STATUS\r
464FatAcquireLockOrFail (\r
b9ec9330
QH
465 VOID\r
466 )\r
467/*++\r
468\r
469Routine Description:\r
470\r
25ce9b1f
QH
471 Lock the volume.\r
472 If the lock is already in the acquired state, then EFI_ACCESS_DENIED is returned.\r
473 Otherwise, EFI_SUCCESS is returned.\r
b9ec9330
QH
474\r
475Arguments:\r
476\r
477 None.\r
478\r
479Returns:\r
480\r
25ce9b1f
QH
481 EFI_SUCCESS - The volume is locked.\r
482 EFI_ACCESS_DENIED - The volume could not be locked because it is already locked.\r
b9ec9330
QH
483\r
484--*/\r
485{\r
25ce9b1f 486 return EfiAcquireLockOrFail (&FatFsLock);\r
b9ec9330
QH
487}\r
488\r
489VOID\r
490FatReleaseLock (\r
491 VOID\r
492 )\r
493/*++\r
494\r
495Routine Description:\r
496\r
497 Unlock the volume.\r
498\r
499Arguments:\r
500\r
501 Null.\r
502\r
503Returns:\r
504\r
505 None.\r
506\r
507--*/\r
508{\r
509 EfiReleaseLock (&FatFsLock);\r
510}\r
511\r
512VOID\r
513FatFreeDirEnt (\r
514 IN FAT_DIRENT *DirEnt\r
515 )\r
516/*++\r
517\r
518Routine Description:\r
519\r
520 Free directory entry.\r
521\r
522Arguments:\r
523\r
524 DirEnt - The directory entry to be freed.\r
525\r
526Returns:\r
527\r
528 None.\r
529\r
530--*/\r
531{\r
532 if (DirEnt->FileString != NULL) {\r
533 FreePool (DirEnt->FileString);\r
534 }\r
535\r
536 FreePool (DirEnt);\r
537}\r
538\r
539VOID\r
540FatFreeVolume (\r
541 IN FAT_VOLUME *Volume\r
542 )\r
543/*++\r
544\r
545Routine Description:\r
546\r
547 Free volume structure (including the contents of directory cache and disk cache).\r
548\r
549Arguments:\r
550\r
551 Volume - The volume structure to be freed.\r
552\r
553Returns:\r
554\r
555 None.\r
556\r
557--*/\r
558{\r
559 //\r
560 // Free disk cache\r
561 //\r
562 if (Volume->CacheBuffer != NULL) {\r
563 FreePool (Volume->CacheBuffer);\r
564 }\r
565 //\r
566 // Free directory cache\r
567 //\r
568 FatCleanupODirCache (Volume);\r
569 FreePool (Volume);\r
570}\r
571\r
572VOID\r
573FatEfiTimeToFatTime (\r
574 IN EFI_TIME *ETime,\r
575 OUT FAT_DATE_TIME *FTime\r
576 )\r
577/*++\r
578\r
579Routine Description:\r
580\r
581 Translate EFI time to FAT time.\r
582\r
583Arguments:\r
584\r
585 ETime - The time of EFI_TIME.\r
586 FTime - The time of FAT_DATE_TIME.\r
587\r
588Returns:\r
589\r
590 None.\r
591\r
592--*/\r
593{\r
594 //\r
595 // ignores timezone info in source ETime\r
596 //\r
597 if (ETime->Year > 1980) {\r
598 FTime->Date.Year = (UINT16) (ETime->Year - 1980);\r
599 }\r
600\r
601 if (ETime->Year >= 1980 + FAT_MAX_YEAR_FROM_1980) {\r
602 FTime->Date.Year = FAT_MAX_YEAR_FROM_1980;\r
603 }\r
604\r
605 FTime->Date.Month = ETime->Month;\r
606 FTime->Date.Day = ETime->Day;\r
607 FTime->Time.Hour = ETime->Hour;\r
608 FTime->Time.Minute = ETime->Minute;\r
609 FTime->Time.DoubleSecond = (UINT16) (ETime->Second / 2);\r
610}\r
611\r
612VOID\r
613FatFatTimeToEfiTime (\r
614 IN FAT_DATE_TIME *FTime,\r
615 OUT EFI_TIME *ETime\r
616 )\r
617/*++\r
618\r
619Routine Description:\r
620\r
621 Translate Fat time to EFI time.\r
622\r
623Arguments:\r
624\r
625 FTime - The time of FAT_DATE_TIME.\r
626 ETime - The time of EFI_TIME.\r
627\r
628Returns:\r
629\r
630 None.\r
631\r
632--*/\r
633{\r
634 ETime->Year = (UINT16) (FTime->Date.Year + 1980);\r
635 ETime->Month = (UINT8) FTime->Date.Month;\r
636 ETime->Day = (UINT8) FTime->Date.Day;\r
637 ETime->Hour = (UINT8) FTime->Time.Hour;\r
638 ETime->Minute = (UINT8) FTime->Time.Minute;\r
639 ETime->Second = (UINT8) (FTime->Time.DoubleSecond * 2);\r
640 ETime->Nanosecond = 0;\r
641 ETime->TimeZone = EFI_UNSPECIFIED_TIMEZONE;\r
642 ETime->Daylight = 0;\r
643}\r
644\r
645VOID\r
646FatGetCurrentFatTime (\r
647 OUT FAT_DATE_TIME *FatNow\r
648 )\r
649/*++\r
650\r
651Routine Description:\r
652\r
653 Get Current FAT time.\r
654\r
655Arguments:\r
656\r
657 FatNow - Current FAT time.\r
658\r
659Returns:\r
660\r
661 None.\r
662\r
663--*/\r
664{\r
ab99061c
OM
665 EFI_STATUS Status;\r
666 EFI_TIME Now;\r
667\r
668 Status = gRT->GetTime (&Now, NULL);\r
669 if (!EFI_ERROR (Status)) {\r
670 FatEfiTimeToFatTime (&Now, FatNow);\r
671 } else {\r
672 ZeroMem (&Now, sizeof (EFI_TIME));\r
673 Now.Year = 1980;\r
674 Now.Month = 1;\r
675 Now.Day = 1;\r
676 FatEfiTimeToFatTime (&Now, FatNow);\r
677 }\r
b9ec9330
QH
678}\r
679\r
680BOOLEAN\r
681FatIsValidTime (\r
682 IN EFI_TIME *Time\r
683 )\r
684/*++\r
685\r
686Routine Description:\r
687\r
688 Check whether a time is valid.\r
689\r
690Arguments:\r
691\r
692 Time - The time of EFI_TIME.\r
693\r
694Returns:\r
695\r
696 TRUE - The time is valid.\r
697 FALSE - The time is not valid.\r
698\r
699--*/\r
700{\r
701 static UINT8 MonthDays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };\r
702 UINTN Day;\r
703 BOOLEAN ValidTime;\r
704\r
705 ValidTime = TRUE;\r
706\r
707 //\r
708 // Check the fields for range problems\r
709 // Fat can only support from 1980\r
710 //\r
711 if (Time->Year < 1980 ||\r
712 Time->Month < 1 ||\r
713 Time->Month > 12 ||\r
714 Time->Day < 1 ||\r
715 Time->Day > 31 ||\r
716 Time->Hour > 23 ||\r
717 Time->Minute > 59 ||\r
718 Time->Second > 59 ||\r
719 Time->Nanosecond > 999999999\r
720 ) {\r
721\r
722 ValidTime = FALSE;\r
723\r
724 } else {\r
725 //\r
726 // Perform a more specific check of the day of the month\r
727 //\r
728 Day = MonthDays[Time->Month - 1];\r
729 if (Time->Month == 2 && IS_LEAP_YEAR (Time->Year)) {\r
730 Day += 1;\r
731 //\r
732 // 1 extra day this month\r
733 //\r
734 }\r
735 if (Time->Day > Day) {\r
736 ValidTime = FALSE;\r
737 }\r
738 }\r
739\r
740 return ValidTime;\r
741}\r