]> git.proxmox.com Git - mirror_edk2.git/blobdiff - FatPkg/EnhancedFatDxe/Misc.c
SecurityPkg/FmpAuthenticationLibPkcs7: Add PKCS7 instance for FMP.
[mirror_edk2.git] / FatPkg / EnhancedFatDxe / Misc.c
index 8774ac8c115b8726fbd6545a0bb53a4bbf40e742..f91759c775c4d7119c7b7b59a268137d6ab10fe5 100644 (file)
@@ -1,7 +1,7 @@
 /*++\r
 \r
-Copyright (c) 2005 - 2010, Intel Corporation\r
-All rights reserved. This program and the accompanying materials are licensed and made available\r
+Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available\r
 under the terms and conditions of the BSD License which accompanies this\r
 distribution. The full text of the license may be found at\r
 http://opensource.org/licenses/bsd-license.php\r
@@ -24,6 +24,220 @@ Revision History
 \r
 #include "Fat.h"\r
 \r
+FAT_TASK *\r
+FatCreateTask (\r
+  FAT_IFILE           *IFile,\r
+  EFI_FILE_IO_TOKEN   *Token\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Create the task\r
+\r
+Arguments:\r
+\r
+  IFile                 - The instance of the open file.\r
+  Token                 - A pointer to the token associated with the transaction.\r
+\r
+Return:\r
+  FAT_TASK *            - Return the task instance.\r
+**/\r
+{\r
+  FAT_TASK            *Task;\r
+\r
+  Task = AllocateZeroPool (sizeof (*Task));\r
+  if (Task != NULL) {\r
+    Task->Signature   = FAT_TASK_SIGNATURE;\r
+    Task->IFile       = IFile;\r
+    Task->FileIoToken = Token;\r
+    InitializeListHead (&Task->Subtasks);\r
+    InitializeListHead (&Task->Link);\r
+  }\r
+  return Task;\r
+}\r
+\r
+VOID\r
+FatDestroyTask (\r
+  FAT_TASK            *Task\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Destroy the task\r
+\r
+Arguments:\r
+\r
+  Task                  - The task to be destroyed.\r
+**/\r
+{\r
+  LIST_ENTRY          *Link;\r
+  FAT_SUBTASK         *Subtask;\r
+\r
+  Link = GetFirstNode (&Task->Subtasks);\r
+  while (!IsNull (&Task->Subtasks, Link)) {\r
+    Subtask = CR (Link, FAT_SUBTASK, Link, FAT_SUBTASK_SIGNATURE);\r
+    Link = FatDestroySubtask (Subtask);\r
+  }\r
+  FreePool (Task);\r
+}\r
+\r
+VOID\r
+FatWaitNonblockingTask (\r
+  FAT_IFILE           *IFile\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Wait all non-blocking requests complete.\r
+\r
+Arguments:\r
+\r
+  IFile                 - The instance of the open file.\r
+**/\r
+{\r
+  BOOLEAN             TaskQueueEmpty;\r
+\r
+  do {\r
+    EfiAcquireLock (&FatTaskLock);\r
+    TaskQueueEmpty = IsListEmpty (&IFile->Tasks);\r
+    EfiReleaseLock (&FatTaskLock);\r
+  } while (!TaskQueueEmpty);\r
+}\r
+\r
+LIST_ENTRY *\r
+FatDestroySubtask (\r
+  FAT_SUBTASK         *Subtask\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Remove the subtask from subtask list.\r
+\r
+Arguments:\r
+\r
+  Subtask               - The subtask to be removed.\r
+\r
+Returns:\r
+\r
+  LIST_ENTRY *          - The next node in the list.\r
+\r
+--*/\r
+{\r
+  LIST_ENTRY          *Link;\r
+\r
+  gBS->CloseEvent (Subtask->DiskIo2Token.Event);\r
+\r
+  Link = RemoveEntryList (&Subtask->Link);\r
+  FreePool (Subtask);\r
+\r
+  return Link;\r
+}\r
+\r
+EFI_STATUS\r
+FatQueueTask (\r
+  IN FAT_IFILE        *IFile,\r
+  IN FAT_TASK         *Task\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Execute the task\r
+\r
+Arguments:\r
+\r
+  IFile                 - The instance of the open file.\r
+  Task                  - The task to be executed.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - The task was executed sucessfully.\r
+  other                 - An error occurred when executing the task.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS          Status;\r
+  LIST_ENTRY          *Link;\r
+  FAT_SUBTASK         *Subtask;\r
+\r
+  //\r
+  // Sometimes the Task doesn't contain any subtasks, signal the event directly.\r
+  //\r
+  if (IsListEmpty (&Task->Subtasks)) {\r
+    Task->FileIoToken->Status = EFI_SUCCESS;\r
+    gBS->SignalEvent (Task->FileIoToken->Event);\r
+    FreePool (Task);\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  EfiAcquireLock (&FatTaskLock);\r
+  InsertTailList (&IFile->Tasks, &Task->Link);\r
+  EfiReleaseLock (&FatTaskLock);\r
+\r
+  Status = EFI_SUCCESS;\r
+  for ( Link = GetFirstNode (&Task->Subtasks)\r
+      ; !IsNull (&Task->Subtasks, Link)\r
+      ; Link = GetNextNode (&Task->Subtasks, Link)\r
+      ) {\r
+    Subtask = CR (Link, FAT_SUBTASK, Link, FAT_SUBTASK_SIGNATURE);\r
+    if (Subtask->Write) {\r
+      \r
+      Status = IFile->OFile->Volume->DiskIo2->WriteDiskEx (\r
+                                                IFile->OFile->Volume->DiskIo2,\r
+                                                IFile->OFile->Volume->MediaId,\r
+                                                Subtask->Offset,\r
+                                                &Subtask->DiskIo2Token,\r
+                                                Subtask->BufferSize,\r
+                                                Subtask->Buffer\r
+                                                );\r
+    } else {\r
+      Status = IFile->OFile->Volume->DiskIo2->ReadDiskEx (\r
+                                                IFile->OFile->Volume->DiskIo2,\r
+                                                IFile->OFile->Volume->MediaId,\r
+                                                Subtask->Offset,\r
+                                                &Subtask->DiskIo2Token,\r
+                                                Subtask->BufferSize,\r
+                                                Subtask->Buffer\r
+                                                );\r
+    }\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    EfiAcquireLock (&FatTaskLock);\r
+    //\r
+    // Remove all the remaining subtasks when failure.\r
+    // We shouldn't remove all the tasks because the non-blocking requests have\r
+    // been submitted and cannot be canceled.\r
+    //\r
+    while (!IsNull (&Task->Subtasks, Link)) {\r
+      Subtask = CR (Link, FAT_SUBTASK, Link, FAT_SUBTASK_SIGNATURE);\r
+      Link = FatDestroySubtask (Subtask);\r
+    }\r
+\r
+    if (IsListEmpty (&Task->Subtasks)) {\r
+      RemoveEntryList (&Task->Link);\r
+      FreePool (Task);\r
+    } else {\r
+      //\r
+      // If one or more subtasks have been already submitted, set FileIoToken\r
+      // to NULL so that the callback won't signal the event.\r
+      //\r
+      Task->FileIoToken = NULL;\r
+    }\r
+\r
+    EfiReleaseLock (&FatTaskLock);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
 EFI_STATUS\r
 FatAccessVolumeDirty (\r
   IN FAT_VOLUME       *Volume,\r
@@ -52,7 +266,79 @@ Returns:
   UINTN WriteCount;\r
 \r
   WriteCount = Volume->FatEntrySize;\r
-  return FatDiskIo (Volume, IoMode, Volume->FatPos + WriteCount, WriteCount, DirtyValue);\r
+  return FatDiskIo (Volume, IoMode, Volume->FatPos + WriteCount, WriteCount, DirtyValue, NULL);\r
+}\r
+\r
+/**\r
+  Invoke a notification event\r
+\r
+  @param  Event                 Event whose notification function is being invoked.\r
+  @param  Context               The pointer to the notification function's context,\r
+                                which is implementation-dependent.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+FatOnAccessComplete (\r
+  IN  EFI_EVENT                Event,\r
+  IN  VOID                     *Context\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Invoke a notification event\r
+  case #1. some subtasks are not completed when the FatOpenEx checks the Task->Subtasks\r
+           - sets Task->SubtaskCollected so callback to signal the event and free the task.\r
+  case #2. all subtasks are completed when the FatOpenEx checks the Task->Subtasks\r
+           - FatOpenEx signal the event and free the task.\r
+Arguments:\r
+\r
+  Event                 - Event whose notification function is being invoked.\r
+  Context               - The pointer to the notification function's context,\r
+                          which is implementation-dependent.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS             Status;\r
+  FAT_SUBTASK            *Subtask;\r
+  FAT_TASK               *Task;\r
+\r
+  //\r
+  // Avoid someone in future breaks the below assumption.\r
+  //\r
+  ASSERT (EfiGetCurrentTpl () == FatTaskLock.Tpl);\r
+\r
+  Subtask = (FAT_SUBTASK *) Context;\r
+  Task    = Subtask->Task;\r
+  Status  = Subtask->DiskIo2Token.TransactionStatus;\r
+\r
+  ASSERT (Task->Signature    == FAT_TASK_SIGNATURE);\r
+  ASSERT (Subtask->Signature == FAT_SUBTASK_SIGNATURE);\r
+\r
+  //\r
+  // Remove the task unconditionally\r
+  //\r
+  FatDestroySubtask (Subtask);\r
+\r
+  //\r
+  // Task->FileIoToken is NULL which means the task will be ignored (just recycle the subtask and task memory).\r
+  //\r
+  if (Task->FileIoToken != NULL) {\r
+    if (IsListEmpty (&Task->Subtasks) || EFI_ERROR (Status)) {\r
+      Task->FileIoToken->Status = Status;\r
+      gBS->SignalEvent (Task->FileIoToken->Event);\r
+      //\r
+      // Mark Task->FileIoToken to NULL so that the subtasks belonging to the task will be ignored.\r
+      //\r
+      Task->FileIoToken = NULL;\r
+    }\r
+  }\r
+\r
+  if (IsListEmpty (&Task->Subtasks)) {\r
+    RemoveEntryList (&Task->Link);\r
+    FreePool (Task);\r
+  }\r
 }\r
 \r
 EFI_STATUS\r
@@ -61,7 +347,8 @@ FatDiskIo (
   IN     IO_MODE          IoMode,\r
   IN     UINT64           Offset,\r
   IN     UINTN            BufferSize,\r
-  IN OUT VOID             *Buffer\r
+  IN OUT VOID             *Buffer,\r
+  IN     FAT_TASK         *Task\r
   )\r
 /*++\r
 \r
@@ -88,6 +375,7 @@ Returns:
   EFI_STATUS            Status;\r
   EFI_DISK_IO_PROTOCOL  *DiskIo;\r
   EFI_DISK_READ         IoFunction;\r
+  FAT_SUBTASK           *Subtask;\r
 \r
   //\r
   // Verify the IO is in devices range\r
@@ -98,20 +386,52 @@ Returns:
       //\r
       // Access cache\r
       //\r
-      Status = FatAccessCache (Volume, CACHE_TYPE (IoMode), RAW_ACCESS (IoMode), Offset, BufferSize, Buffer);\r
+      Status = FatAccessCache (Volume, CACHE_TYPE (IoMode), RAW_ACCESS (IoMode), Offset, BufferSize, Buffer, Task);\r
     } else {\r
       //\r
       // Access disk directly\r
       //\r
-      DiskIo      = Volume->DiskIo;\r
-      IoFunction  = (IoMode == READ_DISK) ? DiskIo->ReadDisk : DiskIo->WriteDisk;\r
-      Status      = IoFunction (DiskIo, Volume->MediaId, Offset, BufferSize, Buffer);\r
+      if (Task == NULL) {\r
+        //\r
+        // Blocking access\r
+        //\r
+        DiskIo      = Volume->DiskIo;\r
+        IoFunction  = (IoMode == READ_DISK) ? DiskIo->ReadDisk : DiskIo->WriteDisk;\r
+        Status      = IoFunction (DiskIo, Volume->MediaId, Offset, BufferSize, Buffer);\r
+      } else {\r
+        //\r
+        // Non-blocking access\r
+        //\r
+        Subtask = AllocateZeroPool (sizeof (*Subtask));\r
+        if (Subtask == NULL) {\r
+          Status        = EFI_OUT_OF_RESOURCES;\r
+        } else {\r
+          Subtask->Signature  = FAT_SUBTASK_SIGNATURE;\r
+          Subtask->Task       = Task;\r
+          Subtask->Write      = (BOOLEAN) (IoMode == WRITE_DISK);\r
+          Subtask->Offset     = Offset;\r
+          Subtask->Buffer     = Buffer;\r
+          Subtask->BufferSize = BufferSize;\r
+          Status = gBS->CreateEvent (\r
+                          EVT_NOTIFY_SIGNAL,\r
+                          TPL_NOTIFY,\r
+                          FatOnAccessComplete,\r
+                          Subtask,\r
+                          &Subtask->DiskIo2Token.Event\r
+                          );\r
+          if (!EFI_ERROR (Status)) {\r
+            InsertTailList (&Task->Subtasks, &Subtask->Link);\r
+          } else {\r
+            FreePool (Subtask);\r
+          }\r
+        }\r
+      }\r
     }\r
   }\r
 \r
   if (EFI_ERROR (Status)) {\r
     Volume->DiskError = TRUE;\r
-    DEBUG ((EFI_D_INFO, "FatDiskIo: error %r\n", Status));\r
+    DEBUG ((EFI_D_ERROR, "FatDiskIo: error %r\n", Status));\r
   }\r
 \r
   return Status;\r
@@ -342,9 +662,19 @@ Returns:
 \r
 --*/\r
 {\r
-  EFI_TIME  Now;\r
-  gRT->GetTime (&Now, NULL);\r
-  FatEfiTimeToFatTime (&Now, FatNow);\r
+  EFI_STATUS Status;\r
+  EFI_TIME   Now;\r
+\r
+  Status = gRT->GetTime (&Now, NULL);\r
+  if (!EFI_ERROR (Status)) {\r
+    FatEfiTimeToFatTime (&Now, FatNow);\r
+  } else {\r
+    ZeroMem (&Now, sizeof (EFI_TIME));\r
+    Now.Year = 1980;\r
+    Now.Month = 1;\r
+    Now.Day = 1;\r
+    FatEfiTimeToFatTime (&Now, FatNow);\r
+  }\r
 }\r
 \r
 BOOLEAN\r