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