aboutsummaryrefslogtreecommitdiffstats
path: root/roms/edk2/FatPkg/EnhancedFatDxe/Misc.c
diff options
context:
space:
mode:
authorAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
committerAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
commitaf1a266670d040d2f4083ff309d732d648afba2a (patch)
tree2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/edk2/FatPkg/EnhancedFatDxe/Misc.c
parente02cda008591317b1625707ff8e115a4841aa889 (diff)
Add submodule dependency filesHEADmaster
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/edk2/FatPkg/EnhancedFatDxe/Misc.c')
-rw-r--r--roms/edk2/FatPkg/EnhancedFatDxe/Misc.c612
1 files changed, 612 insertions, 0 deletions
diff --git a/roms/edk2/FatPkg/EnhancedFatDxe/Misc.c b/roms/edk2/FatPkg/EnhancedFatDxe/Misc.c
new file mode 100644
index 000000000..a005036d4
--- /dev/null
+++ b/roms/edk2/FatPkg/EnhancedFatDxe/Misc.c
@@ -0,0 +1,612 @@
+/** @file
+ Miscellaneous functions.
+
+Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Fat.h"
+UINT8 mMonthDays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+/**
+
+ Create the task
+
+ @param IFile - The instance of the open file.
+ @param Token - A pointer to the token associated with the transaction.
+
+ @return FAT_TASK * - Return the task instance.
+
+**/
+FAT_TASK *
+FatCreateTask (
+ FAT_IFILE *IFile,
+ EFI_FILE_IO_TOKEN *Token
+ )
+{
+ FAT_TASK *Task;
+
+ Task = AllocateZeroPool (sizeof (*Task));
+ if (Task != NULL) {
+ Task->Signature = FAT_TASK_SIGNATURE;
+ Task->IFile = IFile;
+ Task->FileIoToken = Token;
+ InitializeListHead (&Task->Subtasks);
+ InitializeListHead (&Task->Link);
+ }
+ return Task;
+}
+
+/**
+
+ Destroy the task.
+
+ @param Task - The task to be destroyed.
+
+**/
+VOID
+FatDestroyTask (
+ FAT_TASK *Task
+ )
+{
+ LIST_ENTRY *Link;
+ FAT_SUBTASK *Subtask;
+
+ Link = GetFirstNode (&Task->Subtasks);
+ while (!IsNull (&Task->Subtasks, Link)) {
+ Subtask = CR (Link, FAT_SUBTASK, Link, FAT_SUBTASK_SIGNATURE);
+ Link = FatDestroySubtask (Subtask);
+ }
+ FreePool (Task);
+}
+
+/**
+
+ Wait all non-blocking requests complete.
+
+ @param IFile - The instance of the open file.
+
+**/
+VOID
+FatWaitNonblockingTask (
+ FAT_IFILE *IFile
+ )
+{
+ BOOLEAN TaskQueueEmpty;
+
+ do {
+ EfiAcquireLock (&FatTaskLock);
+ TaskQueueEmpty = IsListEmpty (&IFile->Tasks);
+ EfiReleaseLock (&FatTaskLock);
+ } while (!TaskQueueEmpty);
+}
+
+/**
+
+ Remove the subtask from subtask list.
+
+ @param Subtask - The subtask to be removed.
+
+ @return LIST_ENTRY * - The next node in the list.
+
+**/
+LIST_ENTRY *
+FatDestroySubtask (
+ FAT_SUBTASK *Subtask
+ )
+{
+ LIST_ENTRY *Link;
+
+ gBS->CloseEvent (Subtask->DiskIo2Token.Event);
+
+ Link = RemoveEntryList (&Subtask->Link);
+ FreePool (Subtask);
+
+ return Link;
+}
+
+/**
+
+ Execute the task.
+
+ @param IFile - The instance of the open file.
+ @param Task - The task to be executed.
+
+ @retval EFI_SUCCESS - The task was executed successfully.
+ @return other - An error occurred when executing the task.
+
+**/
+EFI_STATUS
+FatQueueTask (
+ IN FAT_IFILE *IFile,
+ IN FAT_TASK *Task
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NextLink;
+ FAT_SUBTASK *Subtask;
+
+ //
+ // Sometimes the Task doesn't contain any subtasks, signal the event directly.
+ //
+ if (IsListEmpty (&Task->Subtasks)) {
+ Task->FileIoToken->Status = EFI_SUCCESS;
+ gBS->SignalEvent (Task->FileIoToken->Event);
+ FreePool (Task);
+ return EFI_SUCCESS;
+ }
+
+ EfiAcquireLock (&FatTaskLock);
+ InsertTailList (&IFile->Tasks, &Task->Link);
+ EfiReleaseLock (&FatTaskLock);
+
+ Status = EFI_SUCCESS;
+ //
+ // Use NextLink to store the next link of the list, because Link might be remove from the
+ // doubly-linked list and get freed in the end of current loop.
+ //
+ // Also, list operation APIs like IsNull() and GetNextNode() are avoided during the loop, since
+ // they may check the validity of doubly-linked lists by traversing them. These APIs cannot
+ // handle list elements being removed during the traverse.
+ //
+ for ( Link = GetFirstNode (&Task->Subtasks), NextLink = GetNextNode (&Task->Subtasks, Link)
+ ; Link != &Task->Subtasks
+ ; Link = NextLink, NextLink = Link->ForwardLink
+ ) {
+ Subtask = CR (Link, FAT_SUBTASK, Link, FAT_SUBTASK_SIGNATURE);
+ if (Subtask->Write) {
+
+ Status = IFile->OFile->Volume->DiskIo2->WriteDiskEx (
+ IFile->OFile->Volume->DiskIo2,
+ IFile->OFile->Volume->MediaId,
+ Subtask->Offset,
+ &Subtask->DiskIo2Token,
+ Subtask->BufferSize,
+ Subtask->Buffer
+ );
+ } else {
+ Status = IFile->OFile->Volume->DiskIo2->ReadDiskEx (
+ IFile->OFile->Volume->DiskIo2,
+ IFile->OFile->Volume->MediaId,
+ Subtask->Offset,
+ &Subtask->DiskIo2Token,
+ Subtask->BufferSize,
+ Subtask->Buffer
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ EfiAcquireLock (&FatTaskLock);
+ //
+ // Remove all the remaining subtasks when failure.
+ // We shouldn't remove all the tasks because the non-blocking requests have
+ // been submitted and cannot be canceled.
+ //
+ while (!IsNull (&Task->Subtasks, Link)) {
+ Subtask = CR (Link, FAT_SUBTASK, Link, FAT_SUBTASK_SIGNATURE);
+ Link = FatDestroySubtask (Subtask);
+ }
+
+ if (IsListEmpty (&Task->Subtasks)) {
+ RemoveEntryList (&Task->Link);
+ FreePool (Task);
+ } else {
+ //
+ // If one or more subtasks have been already submitted, set FileIoToken
+ // to NULL so that the callback won't signal the event.
+ //
+ Task->FileIoToken = NULL;
+ }
+
+ EfiReleaseLock (&FatTaskLock);
+ }
+
+ return Status;
+}
+
+/**
+
+ Set the volume as dirty or not.
+
+ @param Volume - FAT file system volume.
+ @param IoMode - The access mode.
+ @param DirtyValue - Set the volume as dirty or not.
+
+ @retval EFI_SUCCESS - Set the new FAT entry value successfully.
+ @return other - An error occurred when operation the FAT entries.
+
+**/
+EFI_STATUS
+FatAccessVolumeDirty (
+ IN FAT_VOLUME *Volume,
+ IN IO_MODE IoMode,
+ IN VOID *DirtyValue
+ )
+{
+ UINTN WriteCount;
+
+ WriteCount = Volume->FatEntrySize;
+ return FatDiskIo (Volume, IoMode, Volume->FatPos + WriteCount, WriteCount, DirtyValue, NULL);
+}
+
+/**
+ Invoke a notification event.
+
+ @param Event Event whose notification function is being invoked.
+ @param Context The pointer to the notification function's context,
+ which is implementation-dependent.
+
+**/
+VOID
+EFIAPI
+FatOnAccessComplete (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ FAT_SUBTASK *Subtask;
+ FAT_TASK *Task;
+
+ //
+ // Avoid someone in future breaks the below assumption.
+ //
+ ASSERT (EfiGetCurrentTpl () == FatTaskLock.Tpl);
+
+ Subtask = (FAT_SUBTASK *) Context;
+ Task = Subtask->Task;
+ Status = Subtask->DiskIo2Token.TransactionStatus;
+
+ ASSERT (Task->Signature == FAT_TASK_SIGNATURE);
+ ASSERT (Subtask->Signature == FAT_SUBTASK_SIGNATURE);
+
+ //
+ // Remove the task unconditionally
+ //
+ FatDestroySubtask (Subtask);
+
+ //
+ // Task->FileIoToken is NULL which means the task will be ignored (just recycle the subtask and task memory).
+ //
+ if (Task->FileIoToken != NULL) {
+ if (IsListEmpty (&Task->Subtasks) || EFI_ERROR (Status)) {
+ Task->FileIoToken->Status = Status;
+ gBS->SignalEvent (Task->FileIoToken->Event);
+ //
+ // Mark Task->FileIoToken to NULL so that the subtasks belonging to the task will be ignored.
+ //
+ Task->FileIoToken = NULL;
+ }
+ }
+
+ if (IsListEmpty (&Task->Subtasks)) {
+ RemoveEntryList (&Task->Link);
+ FreePool (Task);
+ }
+}
+
+/**
+
+ General disk access function.
+
+ @param Volume - FAT file system volume.
+ @param IoMode - The access mode (disk read/write or cache access).
+ @param Offset - The starting byte offset to read from.
+ @param BufferSize - Size of Buffer.
+ @param Buffer - Buffer containing read data.
+ @param Task point to task instance.
+
+ @retval EFI_SUCCESS - The operation is performed successfully.
+ @retval EFI_VOLUME_CORRUPTED - The access is
+ @return Others - The status of read/write the disk
+
+**/
+EFI_STATUS
+FatDiskIo (
+ IN FAT_VOLUME *Volume,
+ IN IO_MODE IoMode,
+ IN UINT64 Offset,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer,
+ IN FAT_TASK *Task
+ )
+{
+ EFI_STATUS Status;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ EFI_DISK_READ IoFunction;
+ FAT_SUBTASK *Subtask;
+
+ //
+ // Verify the IO is in devices range
+ //
+ Status = EFI_VOLUME_CORRUPTED;
+ if (Offset + BufferSize <= Volume->VolumeSize) {
+ if (CACHE_ENABLED (IoMode)) {
+ //
+ // Access cache
+ //
+ Status = FatAccessCache (Volume, CACHE_TYPE (IoMode), RAW_ACCESS (IoMode), Offset, BufferSize, Buffer, Task);
+ } else {
+ //
+ // Access disk directly
+ //
+ if (Task == NULL) {
+ //
+ // Blocking access
+ //
+ DiskIo = Volume->DiskIo;
+ IoFunction = (IoMode == ReadDisk) ? DiskIo->ReadDisk : DiskIo->WriteDisk;
+ Status = IoFunction (DiskIo, Volume->MediaId, Offset, BufferSize, Buffer);
+ } else {
+ //
+ // Non-blocking access
+ //
+ Subtask = AllocateZeroPool (sizeof (*Subtask));
+ if (Subtask == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ } else {
+ Subtask->Signature = FAT_SUBTASK_SIGNATURE;
+ Subtask->Task = Task;
+ Subtask->Write = (BOOLEAN) (IoMode == WriteDisk);
+ Subtask->Offset = Offset;
+ Subtask->Buffer = Buffer;
+ Subtask->BufferSize = BufferSize;
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ FatOnAccessComplete,
+ Subtask,
+ &Subtask->DiskIo2Token.Event
+ );
+ if (!EFI_ERROR (Status)) {
+ InsertTailList (&Task->Subtasks, &Subtask->Link);
+ } else {
+ FreePool (Subtask);
+ }
+ }
+ }
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ Volume->DiskError = TRUE;
+ DEBUG ((EFI_D_ERROR, "FatDiskIo: error %r\n", Status));
+ }
+
+ return Status;
+}
+
+/**
+
+ Lock the volume.
+
+**/
+VOID
+FatAcquireLock (
+ VOID
+ )
+{
+ EfiAcquireLock (&FatFsLock);
+}
+
+/**
+
+ Lock the volume.
+ If the lock is already in the acquired state, then EFI_ACCESS_DENIED is returned.
+ Otherwise, EFI_SUCCESS is returned.
+
+ @retval EFI_SUCCESS - The volume is locked.
+ @retval EFI_ACCESS_DENIED - The volume could not be locked because it is already locked.
+
+**/
+EFI_STATUS
+FatAcquireLockOrFail (
+ VOID
+ )
+{
+ return EfiAcquireLockOrFail (&FatFsLock);
+}
+
+/**
+
+ Unlock the volume.
+
+**/
+VOID
+FatReleaseLock (
+ VOID
+ )
+{
+ EfiReleaseLock (&FatFsLock);
+}
+
+/**
+
+ Free directory entry.
+
+ @param DirEnt - The directory entry to be freed.
+
+**/
+VOID
+FatFreeDirEnt (
+ IN FAT_DIRENT *DirEnt
+ )
+{
+ if (DirEnt->FileString != NULL) {
+ FreePool (DirEnt->FileString);
+ }
+
+ FreePool (DirEnt);
+}
+
+/**
+
+ Free volume structure (including the contents of directory cache and disk cache).
+
+ @param Volume - The volume structure to be freed.
+
+**/
+VOID
+FatFreeVolume (
+ IN FAT_VOLUME *Volume
+ )
+{
+ //
+ // Free disk cache
+ //
+ if (Volume->CacheBuffer != NULL) {
+ FreePool (Volume->CacheBuffer);
+ }
+ //
+ // Free directory cache
+ //
+ FatCleanupODirCache (Volume);
+ FreePool (Volume);
+}
+
+/**
+
+ Translate EFI time to FAT time.
+
+ @param ETime - The time of EFI_TIME.
+ @param FTime - The time of FAT_DATE_TIME.
+
+**/
+VOID
+FatEfiTimeToFatTime (
+ IN EFI_TIME *ETime,
+ OUT FAT_DATE_TIME *FTime
+ )
+{
+ //
+ // ignores timezone info in source ETime
+ //
+ if (ETime->Year > 1980) {
+ FTime->Date.Year = (UINT16) (ETime->Year - 1980);
+ }
+
+ if (ETime->Year >= 1980 + FAT_MAX_YEAR_FROM_1980) {
+ FTime->Date.Year = FAT_MAX_YEAR_FROM_1980;
+ }
+
+ FTime->Date.Month = ETime->Month;
+ FTime->Date.Day = ETime->Day;
+ FTime->Time.Hour = ETime->Hour;
+ FTime->Time.Minute = ETime->Minute;
+ FTime->Time.DoubleSecond = (UINT16) (ETime->Second / 2);
+}
+
+/**
+
+ Translate Fat time to EFI time.
+
+ @param FTime - The time of FAT_DATE_TIME.
+ @param ETime - The time of EFI_TIME..
+
+**/
+VOID
+FatFatTimeToEfiTime (
+ IN FAT_DATE_TIME *FTime,
+ OUT EFI_TIME *ETime
+ )
+{
+ ETime->Year = (UINT16) (FTime->Date.Year + 1980);
+ ETime->Month = (UINT8) FTime->Date.Month;
+ ETime->Day = (UINT8) FTime->Date.Day;
+ ETime->Hour = (UINT8) FTime->Time.Hour;
+ ETime->Minute = (UINT8) FTime->Time.Minute;
+ ETime->Second = (UINT8) (FTime->Time.DoubleSecond * 2);
+ ETime->Nanosecond = 0;
+ ETime->TimeZone = EFI_UNSPECIFIED_TIMEZONE;
+ ETime->Daylight = 0;
+}
+
+/**
+
+ Get Current FAT time.
+
+ @param FatNow - Current FAT time.
+
+**/
+VOID
+FatGetCurrentFatTime (
+ OUT FAT_DATE_TIME *FatNow
+ )
+{
+ EFI_STATUS Status;
+ EFI_TIME Now;
+
+ Status = gRT->GetTime (&Now, NULL);
+ if (!EFI_ERROR (Status)) {
+ FatEfiTimeToFatTime (&Now, FatNow);
+ } else {
+ ZeroMem (&Now, sizeof (EFI_TIME));
+ Now.Year = 1980;
+ Now.Month = 1;
+ Now.Day = 1;
+ FatEfiTimeToFatTime (&Now, FatNow);
+ }
+}
+
+/**
+
+ Check whether a time is valid.
+
+ @param Time - The time of EFI_TIME.
+
+ @retval TRUE - The time is valid.
+ @retval FALSE - The time is not valid.
+
+**/
+BOOLEAN
+FatIsValidTime (
+ IN EFI_TIME *Time
+ )
+{
+ UINTN Day;
+ BOOLEAN ValidTime;
+
+ ValidTime = TRUE;
+
+ //
+ // Check the fields for range problems
+ // Fat can only support from 1980
+ //
+ if (Time->Year < 1980 ||
+ Time->Month < 1 ||
+ Time->Month > 12 ||
+ Time->Day < 1 ||
+ Time->Day > 31 ||
+ Time->Hour > 23 ||
+ Time->Minute > 59 ||
+ Time->Second > 59 ||
+ Time->Nanosecond > 999999999
+ ) {
+
+ ValidTime = FALSE;
+
+ } else {
+ //
+ // Perform a more specific check of the day of the month
+ //
+ Day = mMonthDays[Time->Month - 1];
+ if (Time->Month == 2 && IS_LEAP_YEAR (Time->Year)) {
+ Day += 1;
+ //
+ // 1 extra day this month
+ //
+ }
+ if (Time->Day > Day) {
+ ValidTime = FALSE;
+ }
+ }
+
+ return ValidTime;
+}