From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- roms/edk2/FatPkg/EnhancedFatDxe/Misc.c | 612 +++++++++++++++++++++++++++++++++ 1 file changed, 612 insertions(+) create mode 100644 roms/edk2/FatPkg/EnhancedFatDxe/Misc.c (limited to 'roms/edk2/FatPkg/EnhancedFatDxe/Misc.c') 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.
+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; +} -- cgit 1.2.3-korg