VirtualBox

Ignore:
Timestamp:
Oct 28, 2015 8:17:18 PM (9 years ago)
Author:
vboxsync
Message:

EFI/Firmware: 'svn merge /vendor/edk2/UDK2010.SR1 /vendor/edk2/current .', reverting and removing files+dirs listed in ReadMe.vbox, resolving conflicts with help from ../UDK2014.SP1/. This is a raw untested merge.

Location:
trunk/src/VBox/Devices/EFI/Firmware
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/EFI/Firmware

  • trunk/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c

    r48674 r58459  
    1010    OverRun  - The last byte is not on a sector boundary.
    1111
    12 Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
     12Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
    1313This program and the accompanying materials
    1414are licensed and made available under the terms and conditions of the BSD License
     
    4646    DiskIoWriteDisk
    4747  },
    48   NULL
     48  {
     49    EFI_DISK_IO2_PROTOCOL_REVISION,
     50    DiskIo2Cancel,
     51    DiskIo2ReadDiskEx,
     52    DiskIo2WriteDiskEx,
     53    DiskIo2FlushDiskEx
     54  }
    4955};
    50 
    5156
    5257/**
     
    9398  //
    9499  gBS->CloseProtocol (
    95         ControllerHandle,
    96         &gEfiBlockIoProtocolGuid,
    97         This->DriverBindingHandle,
    98         ControllerHandle
    99         );
     100         ControllerHandle,
     101         &gEfiBlockIoProtocolGuid,
     102         This->DriverBindingHandle,
     103         ControllerHandle
     104         );
    100105  return EFI_SUCCESS;
    101106}
     
    125130{
    126131  EFI_STATUS            Status;
    127   DISK_IO_PRIVATE_DATA  *Private;
     132  DISK_IO_PRIVATE_DATA  *Instance;
    128133  EFI_TPL               OldTpl;
    129134
     135  Instance = NULL;
     136
    130137  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    131   Private = NULL;
    132 
    133   //
    134   // Connect to the Block IO interface on ControllerHandle.
     138
     139  //
     140  // Connect to the Block IO and Block IO2 interface on ControllerHandle.
    135141  //
    136142  Status = gBS->OpenProtocol (
     
    145151    goto ErrorExit1;
    146152  }
     153
     154  Status = gBS->OpenProtocol (
     155                  ControllerHandle,
     156                  &gEfiBlockIo2ProtocolGuid,
     157                  (VOID **) &gDiskIoPrivateDataTemplate.BlockIo2,
     158                  This->DriverBindingHandle,
     159                  ControllerHandle,
     160                  EFI_OPEN_PROTOCOL_BY_DRIVER
     161                  );
     162  if (EFI_ERROR (Status)) {
     163    gDiskIoPrivateDataTemplate.BlockIo2 = NULL;
     164  }
    147165 
    148166  //
    149167  // Initialize the Disk IO device instance.
    150168  //
    151   Private = AllocateCopyPool (sizeof (DISK_IO_PRIVATE_DATA), &gDiskIoPrivateDataTemplate);
    152   if (Private == NULL) {
     169  Instance = AllocateCopyPool (sizeof (DISK_IO_PRIVATE_DATA), &gDiskIoPrivateDataTemplate);
     170  if (Instance == NULL) {
    153171    Status = EFI_OUT_OF_RESOURCES;
    154172    goto ErrorExit;
     
    156174 
    157175  //
     176  // The BlockSize and IoAlign of BlockIo and BlockIo2 should equal.
     177  //
     178  ASSERT ((Instance->BlockIo2 == NULL) ||
     179          ((Instance->BlockIo->Media->IoAlign == Instance->BlockIo2->Media->IoAlign) &&
     180           (Instance->BlockIo->Media->BlockSize == Instance->BlockIo2->Media->BlockSize)
     181          ));
     182 
     183  InitializeListHead (&Instance->TaskQueue);
     184  EfiInitializeLock (&Instance->TaskQueueLock, TPL_NOTIFY);
     185  Instance->SharedWorkingBuffer = AllocateAlignedPages (
     186                                    EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum) * Instance->BlockIo->Media->BlockSize),
     187                                    Instance->BlockIo->Media->IoAlign
     188                                    );
     189  if (Instance->SharedWorkingBuffer == NULL) {
     190    Status = EFI_OUT_OF_RESOURCES;
     191    goto ErrorExit;
     192  }
     193
     194  //
    158195  // Install protocol interfaces for the Disk IO device.
    159196  //
    160   Status = gBS->InstallProtocolInterface (
    161                   &ControllerHandle,
    162                   &gEfiDiskIoProtocolGuid,
    163                   EFI_NATIVE_INTERFACE,
    164                   &Private->DiskIo
    165                   );
     197  if (Instance->BlockIo2 != NULL) {
     198    Status = gBS->InstallMultipleProtocolInterfaces (
     199                    &ControllerHandle,
     200                    &gEfiDiskIoProtocolGuid,  &Instance->DiskIo,
     201                    &gEfiDiskIo2ProtocolGuid, &Instance->DiskIo2,
     202                    NULL
     203                    );
     204  } else {
     205    Status = gBS->InstallMultipleProtocolInterfaces (
     206                    &ControllerHandle,
     207                    &gEfiDiskIoProtocolGuid,  &Instance->DiskIo,
     208                    NULL
     209                    );
     210  }
    166211
    167212ErrorExit:
    168213  if (EFI_ERROR (Status)) {
    169 
    170     if (Private != NULL) {
    171       FreePool (Private);
     214    if (Instance != NULL && Instance->SharedWorkingBuffer != NULL) {
     215      FreeAlignedPages (
     216        Instance->SharedWorkingBuffer,
     217        EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum) * Instance->BlockIo->Media->BlockSize)
     218        );
     219    }
     220
     221    if (Instance != NULL) {
     222      FreePool (Instance);
    172223    }
    173224
    174225    gBS->CloseProtocol (
    175           ControllerHandle,
    176           &gEfiBlockIoProtocolGuid,
    177           This->DriverBindingHandle,
    178           ControllerHandle
    179           );
     226           ControllerHandle,
     227           &gEfiBlockIoProtocolGuid,
     228           This->DriverBindingHandle,
     229           ControllerHandle
     230           );
    180231  }
    181232
     
    184235  return Status;
    185236}
    186 
    187237
    188238/**
     
    211261  EFI_STATUS            Status;
    212262  EFI_DISK_IO_PROTOCOL  *DiskIo;
    213   DISK_IO_PRIVATE_DATA  *Private;
     263  EFI_DISK_IO2_PROTOCOL *DiskIo2;
     264  DISK_IO_PRIVATE_DATA  *Instance;
     265  BOOLEAN               AllTaskDone;
    214266
    215267  //
     
    225277                  );
    226278  if (EFI_ERROR (Status)) {
    227     return EFI_UNSUPPORTED;
    228   }
    229 
    230   Private = DISK_IO_PRIVATE_DATA_FROM_THIS (DiskIo);
    231 
    232   Status = gBS->UninstallProtocolInterface (
     279    return Status;
     280  }
     281  Status = gBS->OpenProtocol (
    233282                  ControllerHandle,
    234                   &gEfiDiskIoProtocolGuid,
    235                   &Private->DiskIo
     283                  &gEfiDiskIo2ProtocolGuid,
     284                  (VOID **) &DiskIo2,
     285                  This->DriverBindingHandle,
     286                  ControllerHandle,
     287                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
    236288                  );
     289  if (EFI_ERROR (Status)) {
     290    DiskIo2 = NULL;
     291  }
     292 
     293  Instance = DISK_IO_PRIVATE_DATA_FROM_DISK_IO (DiskIo);
     294
     295  if (DiskIo2 != NULL) {
     296    //
     297    // Call BlockIo2::Reset() to terminate any in-flight non-blocking I/O requests
     298    //
     299    ASSERT (Instance->BlockIo2 != NULL);
     300    Status = Instance->BlockIo2->Reset (Instance->BlockIo2, FALSE);
     301    if (EFI_ERROR (Status)) {
     302      return Status;
     303    }
     304    Status = gBS->UninstallMultipleProtocolInterfaces (
     305                    ControllerHandle,
     306                    &gEfiDiskIoProtocolGuid,  &Instance->DiskIo,
     307                    &gEfiDiskIo2ProtocolGuid, &Instance->DiskIo2,
     308                    NULL
     309                    );
     310  } else {
     311    Status = gBS->UninstallMultipleProtocolInterfaces (
     312                    ControllerHandle,
     313                    &gEfiDiskIoProtocolGuid,  &Instance->DiskIo,
     314                    NULL
     315                    );
     316  }
    237317  if (!EFI_ERROR (Status)) {
     318   
     319    do {
     320      EfiAcquireLock (&Instance->TaskQueueLock);
     321      AllTaskDone = IsListEmpty (&Instance->TaskQueue);
     322      EfiReleaseLock (&Instance->TaskQueueLock);
     323    } while (!AllTaskDone);
     324
     325    FreeAlignedPages (
     326      Instance->SharedWorkingBuffer,
     327      EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum) * Instance->BlockIo->Media->BlockSize)
     328      );
     329
    238330    Status = gBS->CloseProtocol (
    239331                    ControllerHandle,
     
    242334                    ControllerHandle
    243335                    );
    244   }
    245 
    246   if (!EFI_ERROR (Status)) {
    247     FreePool (Private);
     336    ASSERT_EFI_ERROR (Status);
     337    if (DiskIo2 != NULL) {
     338      Status = gBS->CloseProtocol (
     339                      ControllerHandle,
     340                      &gEfiBlockIo2ProtocolGuid,
     341                      This->DriverBindingHandle,
     342                      ControllerHandle
     343                      );
     344      ASSERT_EFI_ERROR (Status);
     345    }
     346   
     347    FreePool (Instance);
    248348  }
    249349
     
    252352
    253353
     354/**
     355  Destroy the sub task.
     356
     357  @param Instance     Pointer to the DISK_IO_PRIVATE_DATA.
     358  @param Subtask      Subtask.
     359
     360  @return LIST_ENTRY *  Pointer to the next link of subtask.
     361**/
     362LIST_ENTRY *
     363DiskIoDestroySubtask (
     364  IN DISK_IO_PRIVATE_DATA     *Instance,
     365  IN DISK_IO_SUBTASK          *Subtask
     366  )
     367{
     368  LIST_ENTRY               *Link;
     369
     370  if (Subtask->Task != NULL) {
     371    EfiAcquireLock (&Subtask->Task->SubtasksLock);
     372  }
     373  Link = RemoveEntryList (&Subtask->Link);
     374  if (Subtask->Task != NULL) {
     375    EfiReleaseLock (&Subtask->Task->SubtasksLock);
     376  }
     377
     378  if (!Subtask->Blocking) {
     379    if (Subtask->WorkingBuffer != NULL) {
     380      FreeAlignedPages (
     381        Subtask->WorkingBuffer,
     382        Subtask->Length < Instance->BlockIo->Media->BlockSize
     383        ? EFI_SIZE_TO_PAGES (Instance->BlockIo->Media->BlockSize)
     384        : EFI_SIZE_TO_PAGES (Subtask->Length)
     385        );
     386    }
     387    if (Subtask->BlockIo2Token.Event != NULL) {
     388      gBS->CloseEvent (Subtask->BlockIo2Token.Event);
     389    }
     390  }
     391  FreePool (Subtask);
     392
     393  return Link;
     394}
     395
     396/**
     397  The callback for the BlockIo2 ReadBlocksEx/WriteBlocksEx.
     398  @param  Event                 Event whose notification function is being invoked.
     399  @param  Context               The pointer to the notification function's context,
     400                                which points to the DISK_IO_SUBTASK instance.
     401**/
     402VOID
     403EFIAPI
     404DiskIo2OnReadWriteComplete (
     405  IN EFI_EVENT            Event,
     406  IN VOID                 *Context
     407  )
     408{
     409  DISK_IO_SUBTASK       *Subtask;
     410  DISK_IO2_TASK         *Task;
     411  EFI_STATUS            TransactionStatus;
     412  DISK_IO_PRIVATE_DATA  *Instance;
     413
     414  Subtask           = (DISK_IO_SUBTASK *) Context;
     415  TransactionStatus = Subtask->BlockIo2Token.TransactionStatus;
     416  Task              = Subtask->Task;
     417  Instance          = Task->Instance;
     418
     419  ASSERT (Subtask->Signature  == DISK_IO_SUBTASK_SIGNATURE);
     420  ASSERT (Instance->Signature == DISK_IO_PRIVATE_DATA_SIGNATURE);
     421  ASSERT (Task->Signature     == DISK_IO2_TASK_SIGNATURE);
     422
     423  if ((Subtask->WorkingBuffer != NULL) && !EFI_ERROR (TransactionStatus) &&
     424      (Task->Token != NULL) && !Subtask->Write
     425     ) {
     426    CopyMem (Subtask->Buffer, Subtask->WorkingBuffer + Subtask->Offset, Subtask->Length);
     427  }
     428
     429  DiskIoDestroySubtask (Instance, Subtask);
     430
     431  if (EFI_ERROR (TransactionStatus) || IsListEmpty (&Task->Subtasks)) {
     432    if (Task->Token != NULL) {
     433      //
     434      // Signal error status once the subtask is failed.
     435      // Or signal the last status once the last subtask is finished.
     436      //
     437      Task->Token->TransactionStatus = TransactionStatus;
     438      gBS->SignalEvent (Task->Token->Event);
     439
     440      //
     441      // Mark token to NULL indicating the Task is a dead task.
     442      //
     443      Task->Token = NULL;
     444    }
     445  }
     446}
     447
     448/**
     449  Create the subtask.
     450
     451  @param Write         TRUE: Write request; FALSE: Read request.
     452  @param Lba           The starting logical block address to read from on the device.
     453  @param Offset        The starting byte offset to read from the LBA.
     454  @param Length        The number of bytes to read from the device.
     455  @param WorkingBuffer The aligned buffer to hold the data for reading or writing.
     456  @param Buffer        The buffer to hold the data for reading or writing.
     457  @param Blocking      TRUE: Blocking request; FALSE: Non-blocking request.
     458
     459  @return A pointer to the created subtask.
     460**/
     461DISK_IO_SUBTASK *
     462DiskIoCreateSubtask (
     463  IN BOOLEAN          Write,
     464  IN UINT64           Lba,
     465  IN UINT32           Offset,
     466  IN UINTN            Length,
     467  IN VOID             *WorkingBuffer,  OPTIONAL
     468  IN VOID             *Buffer,
     469  IN BOOLEAN          Blocking
     470  )
     471{
     472  DISK_IO_SUBTASK       *Subtask;
     473  EFI_STATUS            Status;
     474
     475  Subtask = AllocateZeroPool (sizeof (DISK_IO_SUBTASK));
     476  if (Subtask == NULL) {
     477    return NULL;
     478  }
     479  Subtask->Signature     = DISK_IO_SUBTASK_SIGNATURE;
     480  Subtask->Write         = Write;
     481  Subtask->Lba           = Lba;
     482  Subtask->Offset        = Offset;
     483  Subtask->Length        = Length;
     484  Subtask->WorkingBuffer = WorkingBuffer;
     485  Subtask->Buffer        = Buffer;
     486  Subtask->Blocking      = Blocking;
     487  if (!Blocking) {
     488    Status = gBS->CreateEvent (
     489                    EVT_NOTIFY_SIGNAL,
     490                    TPL_NOTIFY,
     491                    DiskIo2OnReadWriteComplete,
     492                    Subtask,
     493                    &Subtask->BlockIo2Token.Event
     494                    );
     495    if (EFI_ERROR (Status)) {
     496      FreePool (Subtask);
     497      return NULL;
     498    }
     499  }
     500  DEBUG ((
     501    EFI_D_BLKIO,
     502    "  %c:Lba/Offset/Length/WorkingBuffer/Buffer = %016lx/%08x/%08x/%08x/%08x\n",
     503    Write ? 'W': 'R', Lba, Offset, Length, WorkingBuffer, Buffer
     504    ));
     505
     506  return Subtask;
     507}
     508
     509/**
     510  Create the subtask list.
     511
     512  @param Instance            Pointer to the DISK_IO_PRIVATE_DATA.
     513  @param Write               TRUE: Write request; FALSE: Read request.
     514  @param Offset              The starting byte offset to read from the device.
     515  @param BufferSize          The size in bytes of Buffer. The number of bytes to read from the device.
     516  @param Buffer              A pointer to the buffer for the data.
     517  @param Blocking            TRUE: Blocking request; FALSE: Non-blocking request.
     518  @param SharedWorkingBuffer The aligned buffer to hold the data for reading or writing.
     519  @param Subtasks            The subtask list header.
     520
     521  @retval TRUE  The subtask list is created successfully.
     522  @retval FALSE The subtask list is not created.
     523**/
     524BOOLEAN
     525DiskIoCreateSubtaskList (
     526  IN DISK_IO_PRIVATE_DATA  *Instance,
     527  IN BOOLEAN               Write,
     528  IN UINT64                Offset,
     529  IN UINTN                 BufferSize,
     530  IN VOID                  *Buffer,
     531  IN BOOLEAN               Blocking,
     532  IN VOID                  *SharedWorkingBuffer,
     533  IN OUT LIST_ENTRY        *Subtasks
     534  )
     535{
     536  UINT32                BlockSize;
     537  UINT32                IoAlign;
     538  UINT64                Lba;
     539  UINT64                OverRunLba;
     540  UINT32                UnderRun;
     541  UINT32                OverRun;
     542  UINT8                 *BufferPtr;
     543  UINTN                 Length;
     544  UINTN                 DataBufferSize;
     545  DISK_IO_SUBTASK       *Subtask;
     546  VOID                  *WorkingBuffer;
     547  LIST_ENTRY            *Link;
     548
     549  DEBUG ((EFI_D_BLKIO, "DiskIo: Create subtasks for task: Offset/BufferSize/Buffer = %016lx/%08x/%08x\n", Offset, BufferSize, Buffer));
     550
     551  BlockSize = Instance->BlockIo->Media->BlockSize;
     552  IoAlign   = Instance->BlockIo->Media->IoAlign;
     553  if (IoAlign == 0) {
     554    IoAlign = 1;
     555  }
     556 
     557  Lba       = DivU64x32Remainder (Offset, BlockSize, &UnderRun);
     558  BufferPtr = (UINT8 *) Buffer;
     559
     560  //
     561  // Special handling for zero BufferSize
     562  //
     563  if (BufferSize == 0) {
     564    Subtask = DiskIoCreateSubtask (Write, Lba, UnderRun, 0, NULL, BufferPtr, Blocking);
     565    if (Subtask == NULL) {
     566      goto Done;
     567    }
     568    InsertTailList (Subtasks, &Subtask->Link);
     569    return TRUE;
     570  }
     571
     572  if (UnderRun != 0) {
     573    Length = MIN (BlockSize - UnderRun, BufferSize);
     574    if (Blocking) {
     575      WorkingBuffer = SharedWorkingBuffer;
     576    } else {
     577      WorkingBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BlockSize), IoAlign);
     578      if (WorkingBuffer == NULL) {
     579        goto Done;
     580      }
     581    }
     582    if (Write) {
     583      //
     584      // A half write operation can be splitted to a blocking block-read and half write operation
     585      // This can simplify the sub task processing logic
     586      //
     587      Subtask = DiskIoCreateSubtask (FALSE, Lba, 0, BlockSize, NULL, WorkingBuffer, TRUE);
     588      if (Subtask == NULL) {
     589        goto Done;
     590      }
     591      InsertTailList (Subtasks, &Subtask->Link);
     592    }
     593
     594    Subtask = DiskIoCreateSubtask (Write, Lba, UnderRun, Length, WorkingBuffer, BufferPtr, Blocking);
     595    if (Subtask == NULL) {
     596      goto Done;
     597    }
     598    InsertTailList (Subtasks, &Subtask->Link);
     599 
     600    BufferPtr  += Length;
     601    Offset     += Length;
     602    BufferSize -= Length;
     603    Lba ++;
     604  }
     605
     606  OverRunLba  = Lba + DivU64x32Remainder (BufferSize, BlockSize, &OverRun);
     607  BufferSize -= OverRun;
     608
     609  if (OverRun != 0) {
     610    if (Blocking) {
     611      WorkingBuffer = SharedWorkingBuffer;
     612    } else {
     613      WorkingBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BlockSize), IoAlign);
     614      if (WorkingBuffer == NULL) {
     615        goto Done;
     616      }
     617    }
     618    if (Write) {
     619      //
     620      // A half write operation can be splitted to a blocking block-read and half write operation
     621      // This can simplify the sub task processing logic
     622      //
     623      Subtask = DiskIoCreateSubtask (FALSE, OverRunLba, 0, BlockSize, NULL, WorkingBuffer, TRUE);
     624      if (Subtask == NULL) {
     625        goto Done;
     626      }
     627      InsertTailList (Subtasks, &Subtask->Link);
     628    }
     629
     630    Subtask = DiskIoCreateSubtask (Write, OverRunLba, 0, OverRun, WorkingBuffer, BufferPtr + BufferSize, Blocking);
     631    if (Subtask == NULL) {
     632      goto Done;
     633    }
     634    InsertTailList (Subtasks, &Subtask->Link);
     635  }
     636 
     637  if (OverRunLba > Lba) {
     638    //
     639    // If the DiskIo maps directly to a BlockIo device do the read.
     640    //
     641    if (ALIGN_POINTER (BufferPtr, IoAlign) == BufferPtr) {
     642      Subtask = DiskIoCreateSubtask (Write, Lba, 0, BufferSize, NULL, BufferPtr, Blocking);
     643      if (Subtask == NULL) {
     644        goto Done;
     645      }
     646      InsertTailList (Subtasks, &Subtask->Link);
     647
     648      BufferPtr  += BufferSize;
     649      Offset     += BufferSize;
     650      BufferSize -= BufferSize;
     651
     652    } else {
     653      if (Blocking) {
     654        //
     655        // Use the allocated buffer instead of the original buffer
     656        // to avoid alignment issue.
     657        //
     658        for (; Lba < OverRunLba; Lba += PcdGet32 (PcdDiskIoDataBufferBlockNum)) {
     659          DataBufferSize = MIN (BufferSize, PcdGet32 (PcdDiskIoDataBufferBlockNum) * BlockSize);
     660
     661          Subtask = DiskIoCreateSubtask (Write, Lba, 0, DataBufferSize, SharedWorkingBuffer, BufferPtr, Blocking);
     662          if (Subtask == NULL) {
     663            goto Done;
     664          }
     665          InsertTailList (Subtasks, &Subtask->Link);
     666
     667          BufferPtr  += DataBufferSize;
     668          Offset     += DataBufferSize;
     669          BufferSize -= DataBufferSize;
     670        }
     671      } else {
     672        WorkingBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), IoAlign);
     673        if (WorkingBuffer == NULL) {
     674          //
     675          // If there is not enough memory, downgrade to blocking access
     676          //
     677          DEBUG ((EFI_D_VERBOSE, "DiskIo: No enough memory so downgrade to blocking access\n"));
     678          if (!DiskIoCreateSubtaskList (Instance, Write, Offset, BufferSize, BufferPtr, TRUE, SharedWorkingBuffer, Subtasks)) {
     679            goto Done;
     680          }
     681        } else {
     682          Subtask = DiskIoCreateSubtask (Write, Lba, 0, BufferSize, WorkingBuffer, BufferPtr, Blocking);
     683          if (Subtask == NULL) {
     684            goto Done;
     685          }
     686          InsertTailList (Subtasks, &Subtask->Link);
     687        }
     688
     689        BufferPtr  += BufferSize;
     690        Offset     += BufferSize;
     691        BufferSize -= BufferSize;
     692      }
     693    }
     694  }
     695
     696  ASSERT (BufferSize == 0);
     697
     698  return TRUE;
     699
     700Done:
     701  //
     702  // Remove all the subtasks.
     703  //
     704  for (Link = GetFirstNode (Subtasks); !IsNull (Subtasks, Link); ) {
     705    Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
     706    Link = DiskIoDestroySubtask (Instance, Subtask);
     707  }
     708  return FALSE;
     709}
     710
     711/**
     712  Terminate outstanding asynchronous requests to a device.
     713
     714  @param This                   Indicates a pointer to the calling context.
     715
     716  @retval EFI_SUCCESS           All outstanding requests were successfully terminated.
     717  @retval EFI_DEVICE_ERROR      The device reported an error while performing the cancel
     718                                operation.
     719**/
     720EFI_STATUS
     721EFIAPI
     722DiskIo2Cancel (
     723  IN EFI_DISK_IO2_PROTOCOL *This
     724  )
     725{
     726  DISK_IO_PRIVATE_DATA  *Instance;
     727  DISK_IO2_TASK         *Task;
     728  LIST_ENTRY            *Link;
     729 
     730  Instance = DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This);
     731
     732  EfiAcquireLock (&Instance->TaskQueueLock);
     733
     734  for (Link = GetFirstNode (&Instance->TaskQueue)
     735    ; !IsNull (&Instance->TaskQueue, Link)
     736    ; Link = GetNextNode (&Instance->TaskQueue, Link)
     737    ) {
     738    Task = CR (Link, DISK_IO2_TASK, Link, DISK_IO2_TASK_SIGNATURE);
     739
     740    if (Task->Token != NULL) {
     741      Task->Token->TransactionStatus = EFI_ABORTED;
     742      gBS->SignalEvent (Task->Token->Event);
     743      //
     744      // Set Token to NULL so that the further BlockIo2 responses will be ignored
     745      //
     746      Task->Token = NULL;
     747    }
     748  }
     749
     750  EfiReleaseLock (&Instance->TaskQueueLock);
     751
     752  return EFI_SUCCESS;
     753}
     754
     755/**
     756  Remove the completed tasks from Instance->TaskQueue. Completed tasks are those who don't have any subtasks.
     757
     758  @param Instance    Pointer to the DISK_IO_PRIVATE_DATA.
     759
     760  @retval TRUE       The Instance->TaskQueue is empty after the completed tasks are removed.
     761  @retval FALSE      The Instance->TaskQueue is not empty after the completed tasks are removed.
     762**/
     763BOOLEAN
     764DiskIo2RemoveCompletedTask (
     765  IN DISK_IO_PRIVATE_DATA     *Instance
     766  )
     767{
     768  BOOLEAN                     QueueEmpty;
     769  LIST_ENTRY                  *Link;
     770  DISK_IO2_TASK               *Task;
     771
     772  QueueEmpty = TRUE;
     773
     774  EfiAcquireLock (&Instance->TaskQueueLock);
     775  for (Link = GetFirstNode (&Instance->TaskQueue); !IsNull (&Instance->TaskQueue, Link); ) {
     776    Task = CR (Link, DISK_IO2_TASK, Link, DISK_IO2_TASK_SIGNATURE);
     777    if (IsListEmpty (&Task->Subtasks)) {
     778      Link = RemoveEntryList (&Task->Link);
     779      ASSERT (Task->Token == NULL);
     780      FreePool (Task);
     781    } else {
     782      Link = GetNextNode (&Instance->TaskQueue, Link);
     783      QueueEmpty = FALSE;
     784    }
     785  }
     786  EfiReleaseLock (&Instance->TaskQueueLock);
     787
     788  return QueueEmpty;
     789}
     790
     791/**
     792  Common routine to access the disk.
     793
     794  @param Instance    Pointer to the DISK_IO_PRIVATE_DATA.
     795  @param Write       TRUE: Write operation; FALSE: Read operation.
     796  @param MediaId     ID of the medium to access.
     797  @param Offset      The starting byte offset on the logical block I/O device to access.
     798  @param Token       A pointer to the token associated with the transaction.
     799                     If this field is NULL, synchronous/blocking IO is performed.
     800  @param  BufferSize            The size in bytes of Buffer. The number of bytes to read from the device.
     801  @param  Buffer                A pointer to the destination buffer for the data.
     802                                The caller is responsible either having implicit or explicit ownership of the buffer.
     803**/
     804EFI_STATUS
     805DiskIo2ReadWriteDisk (
     806  IN DISK_IO_PRIVATE_DATA     *Instance,
     807  IN BOOLEAN                  Write,
     808  IN UINT32                   MediaId,
     809  IN UINT64                   Offset,
     810  IN EFI_DISK_IO2_TOKEN       *Token,
     811  IN UINTN                    BufferSize,
     812  IN UINT8                    *Buffer
     813  )
     814{
     815  EFI_STATUS             Status;
     816  EFI_BLOCK_IO_PROTOCOL  *BlockIo;
     817  EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
     818  EFI_BLOCK_IO_MEDIA     *Media;
     819  LIST_ENTRY             *Link;
     820  LIST_ENTRY             *NextLink;
     821  LIST_ENTRY             Subtasks;
     822  DISK_IO_SUBTASK        *Subtask;
     823  DISK_IO2_TASK          *Task;
     824  EFI_TPL                OldTpl;
     825  BOOLEAN                Blocking;
     826  BOOLEAN                SubtaskBlocking;
     827  LIST_ENTRY             *SubtasksPtr;
     828
     829  Task      = NULL;
     830  BlockIo   = Instance->BlockIo;
     831  BlockIo2  = Instance->BlockIo2;
     832  Media     = BlockIo->Media;
     833  Status    = EFI_SUCCESS;
     834  Blocking  = (BOOLEAN) ((Token == NULL) || (Token->Event == NULL));
     835
     836  if (Media->MediaId != MediaId) {
     837    return EFI_MEDIA_CHANGED;
     838  }
     839 
     840  if (Write && Media->ReadOnly) {
     841    return EFI_WRITE_PROTECTED;
     842  }
     843
     844  if (Blocking) {
     845    //
     846    // Wait till pending async task is completed.
     847    //
     848    while (!DiskIo2RemoveCompletedTask (Instance));
     849
     850    SubtasksPtr = &Subtasks;
     851  } else {
     852    DiskIo2RemoveCompletedTask (Instance);
     853    Task = AllocatePool (sizeof (DISK_IO2_TASK));
     854    if (Task == NULL) {
     855      return EFI_OUT_OF_RESOURCES;
     856    }
     857
     858    EfiAcquireLock (&Instance->TaskQueueLock);
     859    InsertTailList (&Instance->TaskQueue, &Task->Link);
     860    EfiReleaseLock (&Instance->TaskQueueLock);
     861
     862    Task->Signature = DISK_IO2_TASK_SIGNATURE;
     863    Task->Instance  = Instance;
     864    Task->Token     = Token;
     865    EfiInitializeLock (&Task->SubtasksLock, TPL_NOTIFY);
     866
     867    SubtasksPtr = &Task->Subtasks;
     868  }
     869
     870  InitializeListHead (SubtasksPtr);
     871  if (!DiskIoCreateSubtaskList (Instance, Write, Offset, BufferSize, Buffer, Blocking, Instance->SharedWorkingBuffer, SubtasksPtr)) {
     872    if (Task != NULL) {
     873      FreePool (Task);
     874    }
     875    return EFI_OUT_OF_RESOURCES;
     876  }
     877  ASSERT (!IsListEmpty (SubtasksPtr));
     878
     879  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
     880  for ( Link = GetFirstNode (SubtasksPtr), NextLink = GetNextNode (SubtasksPtr, Link)
     881      ; !IsNull (SubtasksPtr, Link)
     882      ; Link = NextLink, NextLink = GetNextNode (SubtasksPtr, NextLink)
     883      ) {
     884    Subtask         = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
     885    Subtask->Task   = Task;
     886    SubtaskBlocking = Subtask->Blocking;
     887
     888    ASSERT ((Subtask->Length % Media->BlockSize == 0) || (Subtask->Length < Media->BlockSize));
     889
     890    if (Subtask->Write) {
     891      //
     892      // Write
     893      //
     894      if (Subtask->WorkingBuffer != NULL) {
     895        //
     896        // A sub task before this one should be a block read operation, causing the WorkingBuffer filled with the entire one block data.
     897        //
     898        CopyMem (Subtask->WorkingBuffer + Subtask->Offset, Subtask->Buffer, Subtask->Length);
     899      }
     900
     901      if (SubtaskBlocking) {
     902        Status = BlockIo->WriteBlocks (
     903                            BlockIo,
     904                            MediaId,
     905                            Subtask->Lba,
     906                            (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
     907                            (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
     908                            );
     909      } else {
     910        Status = BlockIo2->WriteBlocksEx (
     911                             BlockIo2,
     912                             MediaId,
     913                             Subtask->Lba,
     914                             &Subtask->BlockIo2Token,
     915                             (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
     916                             (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
     917                             );
     918      }
     919
     920    } else {
     921      //
     922      // Read
     923      //
     924      if (SubtaskBlocking) {
     925        Status = BlockIo->ReadBlocks (
     926                            BlockIo,
     927                            MediaId,
     928                            Subtask->Lba,
     929                            (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
     930                            (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
     931                            );
     932        if (!EFI_ERROR (Status) && (Subtask->WorkingBuffer != NULL)) {
     933          CopyMem (Subtask->Buffer, Subtask->WorkingBuffer + Subtask->Offset, Subtask->Length);
     934        }
     935      } else {
     936        Status = BlockIo2->ReadBlocksEx (
     937                             BlockIo2,
     938                             MediaId,
     939                             Subtask->Lba,
     940                             &Subtask->BlockIo2Token,
     941                             (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
     942                             (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
     943                             );
     944      }
     945    }
     946
     947    if (SubtaskBlocking || EFI_ERROR (Status)) {
     948      //
     949      // Make sure the subtask list only contains non-blocking subtasks.
     950      // Remove failed non-blocking subtasks as well because the callback won't be called.
     951      //
     952      DiskIoDestroySubtask (Instance, Subtask);
     953    }
     954
     955    if (EFI_ERROR (Status)) {
     956      break;
     957    }
     958  }
     959 
     960  gBS->RaiseTPL (TPL_NOTIFY);
     961
     962  //
     963  // Remove all the remaining subtasks when failure.
     964  // We shouldn't remove all the tasks because the non-blocking requests have been submitted and cannot be canceled.
     965  //
     966  if (EFI_ERROR (Status)) {
     967    while (!IsNull (SubtasksPtr, NextLink)) {
     968      Subtask = CR (NextLink, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
     969      NextLink = DiskIoDestroySubtask (Instance, Subtask);
     970    }
     971  }
     972
     973  //
     974  // It's possible that the non-blocking subtasks finish before raising TPL to NOTIFY,
     975  // so the subtasks list might be empty at this point.
     976  //
     977  if (!Blocking && IsListEmpty (SubtasksPtr)) {
     978    EfiAcquireLock (&Instance->TaskQueueLock);
     979    RemoveEntryList (&Task->Link);
     980    EfiReleaseLock (&Instance->TaskQueueLock);
     981
     982    if (!EFI_ERROR (Status) && (Task->Token != NULL)) {
     983      //
     984      // Task->Token should be set to NULL by the DiskIo2OnReadWriteComplete
     985      // It it's not, that means the non-blocking request was downgraded to blocking request.
     986      //
     987      DEBUG ((EFI_D_VERBOSE, "DiskIo: Non-blocking request was downgraded to blocking request, signal event directly.\n"));
     988      Task->Token->TransactionStatus = Status;
     989      gBS->SignalEvent (Task->Token->Event);
     990    }
     991
     992    FreePool (Task);
     993  }
     994
     995  gBS->RestoreTPL (OldTpl);
     996
     997  return Status;
     998}
     999
     1000/**
     1001  Reads a specified number of bytes from a device.
     1002
     1003  @param This                   Indicates a pointer to the calling context.
     1004  @param MediaId                ID of the medium to be read.
     1005  @param Offset                 The starting byte offset on the logical block I/O device to read from.
     1006  @param Token                  A pointer to the token associated with the transaction.
     1007                                If this field is NULL, synchronous/blocking IO is performed.
     1008  @param  BufferSize            The size in bytes of Buffer. The number of bytes to read from the device.
     1009  @param  Buffer                A pointer to the destination buffer for the data.
     1010                                The caller is responsible either having implicit or explicit ownership of the buffer.
     1011
     1012  @retval EFI_SUCCESS           If Event is NULL (blocking I/O): The data was read correctly from the device.
     1013                                If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
     1014                                                                         Event will be signaled upon completion.
     1015  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
     1016  @retval EFI_NO_MEDIA          There is no medium in the device.
     1017  @retval EFI_MEDIA_CHNAGED     The MediaId is not for the current medium.
     1018  @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not valid for the device.
     1019  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
     1020
     1021**/
     1022EFI_STATUS
     1023EFIAPI
     1024DiskIo2ReadDiskEx (
     1025  IN EFI_DISK_IO2_PROTOCOL        *This,
     1026  IN UINT32                       MediaId,
     1027  IN UINT64                       Offset,
     1028  IN OUT EFI_DISK_IO2_TOKEN       *Token,
     1029  IN UINTN                        BufferSize,
     1030  OUT VOID                        *Buffer
     1031  )
     1032{
     1033  return DiskIo2ReadWriteDisk (
     1034           DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This),
     1035           FALSE, MediaId, Offset, Token, BufferSize, (UINT8 *) Buffer
     1036           );
     1037}
     1038
     1039/**
     1040  Writes a specified number of bytes to a device.
     1041
     1042  @param This        Indicates a pointer to the calling context.
     1043  @param MediaId     ID of the medium to be written.
     1044  @param Offset      The starting byte offset on the logical block I/O device to write to.
     1045  @param Token       A pointer to the token associated with the transaction.
     1046                     If this field is NULL, synchronous/blocking IO is performed.
     1047  @param BufferSize  The size in bytes of Buffer. The number of bytes to write to the device.
     1048  @param Buffer      A pointer to the buffer containing the data to be written.
     1049
     1050  @retval EFI_SUCCESS           If Event is NULL (blocking I/O): The data was written correctly to the device.
     1051                                If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
     1052                                                                         Event will be signaled upon completion.
     1053  @retval EFI_WRITE_PROTECTED   The device cannot be written to.
     1054  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write operation.
     1055  @retval EFI_NO_MEDIA          There is no medium in the device.
     1056  @retval EFI_MEDIA_CHNAGED     The MediaId is not for the current medium.
     1057  @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not valid for the device.
     1058  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
     1059
     1060**/
     1061EFI_STATUS
     1062EFIAPI
     1063DiskIo2WriteDiskEx (
     1064  IN EFI_DISK_IO2_PROTOCOL        *This,
     1065  IN UINT32                       MediaId,
     1066  IN UINT64                       Offset,
     1067  IN OUT EFI_DISK_IO2_TOKEN       *Token,
     1068  IN UINTN                        BufferSize,
     1069  IN VOID                         *Buffer
     1070  )
     1071{
     1072  return DiskIo2ReadWriteDisk (
     1073           DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This),
     1074           TRUE, MediaId, Offset, Token, BufferSize, (UINT8 *) Buffer
     1075           );
     1076}
     1077
     1078/**
     1079  The callback for the BlockIo2 FlushBlocksEx.
     1080  @param  Event                 Event whose notification function is being invoked.
     1081  @param  Context               The pointer to the notification function's context,
     1082                                which points to the DISK_IO2_FLUSH_TASK instance.
     1083**/
     1084VOID
     1085EFIAPI
     1086DiskIo2OnFlushComplete (
     1087  IN EFI_EVENT                 Event,
     1088  IN VOID                      *Context
     1089  )
     1090{
     1091  DISK_IO2_FLUSH_TASK             *Task;
     1092
     1093  gBS->CloseEvent (Event);
     1094
     1095  Task = (DISK_IO2_FLUSH_TASK *) Context;
     1096  ASSERT (Task->Signature == DISK_IO2_FLUSH_TASK_SIGNATURE);
     1097  Task->Token->TransactionStatus = Task->BlockIo2Token.TransactionStatus;
     1098  gBS->SignalEvent (Task->Token->Event);
     1099
     1100  FreePool (Task);
     1101}
     1102
     1103/**
     1104  Flushes all modified data to the physical device.
     1105
     1106  @param This        Indicates a pointer to the calling context.
     1107  @param Token       A pointer to the token associated with the transaction.
     1108                     If this field is NULL, synchronous/blocking IO is performed.
     1109
     1110  @retval EFI_SUCCESS           If Event is NULL (blocking I/O): The data was flushed successfully to the device.
     1111                                If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
     1112                                                                         Event will be signaled upon completion.
     1113  @retval EFI_WRITE_PROTECTED   The device cannot be written to.
     1114  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write operation.
     1115  @retval EFI_NO_MEDIA          There is no medium in the device.
     1116  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
     1117**/
     1118EFI_STATUS
     1119EFIAPI
     1120DiskIo2FlushDiskEx (
     1121  IN EFI_DISK_IO2_PROTOCOL        *This,
     1122  IN OUT EFI_DISK_IO2_TOKEN       *Token
     1123  )
     1124{
     1125  EFI_STATUS                      Status;
     1126  DISK_IO2_FLUSH_TASK             *Task;
     1127  DISK_IO_PRIVATE_DATA            *Private;
     1128
     1129  Private = DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This);
     1130
     1131  if ((Token != NULL) && (Token->Event != NULL)) {
     1132    Task = AllocatePool (sizeof (DISK_IO2_FLUSH_TASK));
     1133    if (Task == NULL) {
     1134      return EFI_OUT_OF_RESOURCES;
     1135    }
     1136
     1137    Status = gBS->CreateEvent (
     1138                    EVT_NOTIFY_SIGNAL,
     1139                    TPL_CALLBACK,
     1140                    DiskIo2OnFlushComplete,
     1141                    Task,
     1142                    &Task->BlockIo2Token.Event
     1143                    );
     1144    if (EFI_ERROR (Status)) {
     1145      FreePool (Task);
     1146      return Status;
     1147    }
     1148    Task->Signature = DISK_IO2_FLUSH_TASK_SIGNATURE;
     1149    Task->Token     = Token;
     1150    Status = Private->BlockIo2->FlushBlocksEx (Private->BlockIo2, &Task->BlockIo2Token);
     1151    if (EFI_ERROR (Status)) {
     1152      gBS->CloseEvent (Task->BlockIo2Token.Event);
     1153      FreePool (Task);
     1154    }
     1155  } else {
     1156    Status = Private->BlockIo2->FlushBlocksEx (Private->BlockIo2, NULL);
     1157  }
     1158
     1159  return Status;
     1160}
    2541161
    2551162/**
     
    2861193  )
    2871194{
    288   EFI_STATUS            Status;
    289   DISK_IO_PRIVATE_DATA  *Private;
    290   EFI_BLOCK_IO_PROTOCOL *BlockIo;
    291   EFI_BLOCK_IO_MEDIA    *Media;
    292   UINT32                BlockSize;
    293   UINT64                Lba;
    294   UINT64                OverRunLba;
    295   UINT32                UnderRun;
    296   UINT32                OverRun;
    297   BOOLEAN               TransactionComplete;
    298   UINTN                 WorkingBufferSize;
    299   UINT8                 *WorkingBuffer;
    300   UINTN                 Length;
    301   UINT8                 *Data;
    302   UINT8                 *PreData;
    303   UINTN                 IsBufferAligned;
    304   UINTN                 DataBufferSize;
    305   BOOLEAN               LastRead;
    306 
    307   Private   = DISK_IO_PRIVATE_DATA_FROM_THIS (This);
    308 
    309   BlockIo   = Private->BlockIo;
    310   Media     = BlockIo->Media;
    311   BlockSize = Media->BlockSize;
    312 
    313   if (Media->MediaId != MediaId) {
    314     return EFI_MEDIA_CHANGED;
    315   }
    316 
    317   WorkingBuffer     = Buffer;
    318   WorkingBufferSize = BufferSize;
    319 
    320   //
    321   // Allocate a temporary buffer for operation
    322   //
    323   DataBufferSize = BlockSize * DATA_BUFFER_BLOCK_NUM;
    324 
    325   if (Media->IoAlign > 1) {
    326     PreData = AllocatePool (DataBufferSize + Media->IoAlign);
    327     Data    = PreData - ((UINTN) PreData & (Media->IoAlign - 1)) + Media->IoAlign;
    328   } else {
    329     PreData = AllocatePool (DataBufferSize);
    330     Data    = PreData;
    331   }
    332 
    333   if (PreData == NULL) {
    334     return EFI_OUT_OF_RESOURCES;
    335   }
    336 
    337   Lba                 = DivU64x32Remainder (Offset, BlockSize, &UnderRun);
    338 
    339   Length              = BlockSize - UnderRun;
    340   TransactionComplete = FALSE;
    341 
    342   Status              = EFI_SUCCESS;
    343   if (UnderRun != 0) {
    344     //
    345     // Offset starts in the middle of an Lba, so read the entire block.
    346     //
    347     Status = BlockIo->ReadBlocks (
    348                         BlockIo,
    349                         MediaId,
    350                         Lba,
    351                         BlockSize,
    352                         Data
    353                         );
    354 
    355     if (EFI_ERROR (Status)) {
    356       goto Done;
    357     }
    358 
    359     if (Length > BufferSize) {
    360       Length              = BufferSize;
    361       TransactionComplete = TRUE;
    362     }
    363 
    364     CopyMem (WorkingBuffer, Data + UnderRun, Length);
    365 
    366     WorkingBuffer += Length;
    367 
    368     WorkingBufferSize -= Length;
    369     if (WorkingBufferSize == 0) {
    370       goto Done;
    371     }
    372 
    373     Lba += 1;
    374   }
    375 
    376   OverRunLba = Lba + DivU64x32Remainder (WorkingBufferSize, BlockSize, &OverRun);
    377 
    378   if (!TransactionComplete && WorkingBufferSize >= BlockSize) {
    379     //
    380     // If the DiskIo maps directly to a BlockIo device do the read.
    381     //
    382     if (OverRun != 0) {
    383       WorkingBufferSize -= OverRun;
    384     }
    385     //
    386     // Check buffer alignment
    387     //
    388     IsBufferAligned = (UINTN) WorkingBuffer & (UINTN) (Media->IoAlign - 1);
    389 
    390     if (Media->IoAlign <= 1 || IsBufferAligned == 0) {
    391       //
    392       // Alignment is satisfied, so read them together
    393       //
    394       Status = BlockIo->ReadBlocks (
    395                           BlockIo,
    396                           MediaId,
    397                           Lba,
    398                           WorkingBufferSize,
    399                           WorkingBuffer
    400                           );
    401 
    402       if (EFI_ERROR (Status)) {
    403         goto Done;
    404       }
    405 
    406       WorkingBuffer += WorkingBufferSize;
    407 
    408     } else {
    409       //
    410       // Use the allocated buffer instead of the original buffer
    411       // to avoid alignment issue.
    412       // Here, the allocated buffer (8-byte align) can satisfy the alignment
    413       //
    414       LastRead = FALSE;
    415       do {
    416         if (WorkingBufferSize <= DataBufferSize) {
    417           //
    418           // It is the last calling to readblocks in this loop
    419           //
    420           DataBufferSize  = WorkingBufferSize;
    421           LastRead        = TRUE;
    422         }
    423 
    424         Status = BlockIo->ReadBlocks (
    425                             BlockIo,
    426                             MediaId,
    427                             Lba,
    428                             DataBufferSize,
    429                             Data
    430                             );
    431         if (EFI_ERROR (Status)) {
    432           goto Done;
    433         }
    434 
    435         CopyMem (WorkingBuffer, Data, DataBufferSize);
    436         WorkingBufferSize -= DataBufferSize;
    437         WorkingBuffer += DataBufferSize;
    438         Lba += DATA_BUFFER_BLOCK_NUM;
    439       } while (!LastRead);
    440     }
    441   }
    442 
    443   if (!TransactionComplete && OverRun != 0) {
    444     //
    445     // Last read is not a complete block.
    446     //
    447     Status = BlockIo->ReadBlocks (
    448                         BlockIo,
    449                         MediaId,
    450                         OverRunLba,
    451                         BlockSize,
    452                         Data
    453                         );
    454 
    455     if (EFI_ERROR (Status)) {
    456       goto Done;
    457     }
    458 
    459     CopyMem (WorkingBuffer, Data, OverRun);
    460   }
    461 
    462 Done:
    463   if (PreData != NULL) {
    464     FreePool (PreData);
    465   }
    466 
    467   return Status;
     1195  return DiskIo2ReadWriteDisk (
     1196           DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This),
     1197           FALSE, MediaId, Offset, NULL, BufferSize, (UINT8 *) Buffer
     1198           );
    4681199}
    4691200
     
    5041235  )
    5051236{
    506   EFI_STATUS            Status;
    507   DISK_IO_PRIVATE_DATA  *Private;
    508   EFI_BLOCK_IO_PROTOCOL *BlockIo;
    509   EFI_BLOCK_IO_MEDIA    *Media;
    510   UINT32                BlockSize;
    511   UINT64                Lba;
    512   UINT64                OverRunLba;
    513   UINT32                UnderRun;
    514   UINT32                OverRun;
    515   BOOLEAN               TransactionComplete;
    516   UINTN                 WorkingBufferSize;
    517   UINT8                 *WorkingBuffer;
    518   UINTN                 Length;
    519   UINT8                 *Data;
    520   UINT8                 *PreData;
    521   UINTN                 IsBufferAligned;
    522   UINTN                 DataBufferSize;
    523   BOOLEAN               LastWrite;
    524 
    525   Private   = DISK_IO_PRIVATE_DATA_FROM_THIS (This);
    526 
    527   BlockIo   = Private->BlockIo;
    528   Media     = BlockIo->Media;
    529   BlockSize = Media->BlockSize;
    530 
    531   if (Media->ReadOnly) {
    532     return EFI_WRITE_PROTECTED;
    533   }
    534 
    535   if (Media->MediaId != MediaId) {
    536     return EFI_MEDIA_CHANGED;
    537   }
    538 
    539   DataBufferSize = BlockSize * DATA_BUFFER_BLOCK_NUM;
    540 
    541   if (Media->IoAlign > 1) {
    542     PreData = AllocatePool (DataBufferSize + Media->IoAlign);
    543     Data    = PreData - ((UINTN) PreData & (Media->IoAlign - 1)) + Media->IoAlign;
    544   } else {
    545     PreData = AllocatePool (DataBufferSize);
    546     Data    = PreData;
    547   }
    548 
    549   if (PreData == NULL) {
    550     return EFI_OUT_OF_RESOURCES;
    551   }
    552 
    553   WorkingBuffer       = Buffer;
    554   WorkingBufferSize   = BufferSize;
    555 
    556   Lba                 = DivU64x32Remainder (Offset, BlockSize, &UnderRun);
    557 
    558   Length              = BlockSize - UnderRun;
    559   TransactionComplete = FALSE;
    560 
    561   Status              = EFI_SUCCESS;
    562   if (UnderRun != 0) {
    563     //
    564     // Offset starts in the middle of an Lba, so do read modify write.
    565     //
    566     Status = BlockIo->ReadBlocks (
    567                         BlockIo,
    568                         MediaId,
    569                         Lba,
    570                         BlockSize,
    571                         Data
    572                         );
    573 
    574     if (EFI_ERROR (Status)) {
    575       goto Done;
    576     }
    577 
    578     if (Length > BufferSize) {
    579       Length              = BufferSize;
    580       TransactionComplete = TRUE;
    581     }
    582 
    583     CopyMem (Data + UnderRun, WorkingBuffer, Length);
    584 
    585     Status = BlockIo->WriteBlocks (
    586                         BlockIo,
    587                         MediaId,
    588                         Lba,
    589                         BlockSize,
    590                         Data
    591                         );
    592     if (EFI_ERROR (Status)) {
    593       goto Done;
    594     }
    595 
    596     WorkingBuffer += Length;
    597     WorkingBufferSize -= Length;
    598     if (WorkingBufferSize == 0) {
    599       goto Done;
    600     }
    601 
    602     Lba += 1;
    603   }
    604 
    605   OverRunLba = Lba + DivU64x32Remainder (WorkingBufferSize, BlockSize, &OverRun);
    606 
    607   if (!TransactionComplete && WorkingBufferSize >= BlockSize) {
    608     //
    609     // If the DiskIo maps directly to a BlockIo device do the write.
    610     //
    611     if (OverRun != 0) {
    612       WorkingBufferSize -= OverRun;
    613     }
    614     //
    615     // Check buffer alignment
    616     //
    617     IsBufferAligned = (UINTN) WorkingBuffer & (UINTN) (Media->IoAlign - 1);
    618 
    619     if (Media->IoAlign <= 1 || IsBufferAligned == 0) {
    620       //
    621       // Alignment is satisfied, so write them together
    622       //
    623       Status = BlockIo->WriteBlocks (
    624                           BlockIo,
    625                           MediaId,
    626                           Lba,
    627                           WorkingBufferSize,
    628                           WorkingBuffer
    629                           );
    630 
    631       if (EFI_ERROR (Status)) {
    632         goto Done;
    633       }
    634 
    635       WorkingBuffer += WorkingBufferSize;
    636 
    637     } else {
    638       //
    639       // The buffer parameter is not aligned with the request
    640       // So use the allocated instead.
    641       // It can fit almost all the cases.
    642       //
    643       LastWrite = FALSE;
    644       do {
    645         if (WorkingBufferSize <= DataBufferSize) {
    646           //
    647           // It is the last calling to writeblocks in this loop
    648           //
    649           DataBufferSize  = WorkingBufferSize;
    650           LastWrite       = TRUE;
    651         }
    652 
    653         CopyMem (Data, WorkingBuffer, DataBufferSize);
    654         Status = BlockIo->WriteBlocks (
    655                             BlockIo,
    656                             MediaId,
    657                             Lba,
    658                             DataBufferSize,
    659                             Data
    660                             );
    661         if (EFI_ERROR (Status)) {
    662           goto Done;
    663         }
    664 
    665         WorkingBufferSize -= DataBufferSize;
    666         WorkingBuffer += DataBufferSize;
    667         Lba += DATA_BUFFER_BLOCK_NUM;
    668       } while (!LastWrite);
    669     }
    670   }
    671 
    672   if (!TransactionComplete && OverRun != 0) {
    673     //
    674     // Last bit is not a complete block, so do a read modify write.
    675     //
    676     Status = BlockIo->ReadBlocks (
    677                         BlockIo,
    678                         MediaId,
    679                         OverRunLba,
    680                         BlockSize,
    681                         Data
    682                         );
    683 
    684     if (EFI_ERROR (Status)) {
    685       goto Done;
    686     }
    687 
    688     CopyMem (Data, WorkingBuffer, OverRun);
    689 
    690     Status = BlockIo->WriteBlocks (
    691                         BlockIo,
    692                         MediaId,
    693                         OverRunLba,
    694                         BlockSize,
    695                         Data
    696                         );
    697     if (EFI_ERROR (Status)) {
    698       goto Done;
    699     }
    700   }
    701 
    702 Done:
    703   if (PreData != NULL) {
    704     FreePool (PreData);
    705   }
    706 
    707   return Status;
    708 }
    709 
     1237  return DiskIo2ReadWriteDisk (
     1238           DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This),
     1239           TRUE, MediaId, Offset, NULL, BufferSize, (UINT8 *) Buffer
     1240           );
     1241}
    7101242
    7111243/**
     
    7411273  ASSERT_EFI_ERROR (Status);
    7421274
    743 
    7441275  return Status;
    7451276}
    746 
  • trunk/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.h

    r48674 r58459  
    22  Master header file for DiskIo driver. It includes the module private defininitions.
    33
    4 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
     4Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
    55This program and the accompanying materials
    66are licensed and made available under the terms and conditions of the BSD License
     
    1818#include <Uefi.h>
    1919#include <Protocol/BlockIo.h>
     20#include <Protocol/BlockIo2.h>
     21#include <Protocol/DiskIo2.h>
    2022#include <Protocol/ComponentName.h>
    2123#include <Protocol/DriverBinding.h>
     
    2931#include <Library/UefiBootServicesTableLib.h>
    3032
    31 
    32 #define DATA_BUFFER_BLOCK_NUM             64
    33 
    3433#define DISK_IO_PRIVATE_DATA_SIGNATURE  SIGNATURE_32 ('d', 's', 'k', 'I')
    35 
    3634typedef struct {
    37   UINTN                 Signature;
    38   EFI_DISK_IO_PROTOCOL  DiskIo;
    39   EFI_BLOCK_IO_PROTOCOL *BlockIo;
     35  UINT32                          Signature;
     36
     37  EFI_DISK_IO_PROTOCOL            DiskIo;
     38  EFI_DISK_IO2_PROTOCOL           DiskIo2;
     39  EFI_BLOCK_IO_PROTOCOL           *BlockIo;
     40  EFI_BLOCK_IO2_PROTOCOL          *BlockIo2;
     41
     42  UINT8                           *SharedWorkingBuffer;
     43
     44  EFI_LOCK                        TaskQueueLock;
     45  LIST_ENTRY                      TaskQueue;
    4046} DISK_IO_PRIVATE_DATA;
    41 
    42 #define DISK_IO_PRIVATE_DATA_FROM_THIS(a) CR (a, DISK_IO_PRIVATE_DATA, DiskIo, DISK_IO_PRIVATE_DATA_SIGNATURE)
     47#define DISK_IO_PRIVATE_DATA_FROM_DISK_IO(a)  CR (a, DISK_IO_PRIVATE_DATA, DiskIo,  DISK_IO_PRIVATE_DATA_SIGNATURE)
     48#define DISK_IO_PRIVATE_DATA_FROM_DISK_IO2(a) CR (a, DISK_IO_PRIVATE_DATA, DiskIo2, DISK_IO_PRIVATE_DATA_SIGNATURE)
     49
     50#define DISK_IO2_TASK_SIGNATURE   SIGNATURE_32 ('d', 'i', 'a', 't')
     51typedef struct {
     52  UINT32                          Signature;
     53  LIST_ENTRY                      Link;     /// < link to other task
     54  EFI_LOCK                        SubtasksLock;
     55  LIST_ENTRY                      Subtasks; /// < header of subtasks
     56  EFI_DISK_IO2_TOKEN              *Token;
     57  DISK_IO_PRIVATE_DATA            *Instance;
     58} DISK_IO2_TASK;
     59
     60#define DISK_IO2_FLUSH_TASK_SIGNATURE SIGNATURE_32 ('d', 'i', 'f', 't')
     61typedef struct {
     62  UINT32                          Signature;
     63  EFI_BLOCK_IO2_TOKEN             BlockIo2Token;
     64  EFI_DISK_IO2_TOKEN              *Token;
     65} DISK_IO2_FLUSH_TASK;
     66
     67#define DISK_IO_SUBTASK_SIGNATURE SIGNATURE_32 ('d', 'i', 's', 't')
     68typedef struct {
     69  //
     70  // UnderRun:  Offset != 0, Length < BlockSize
     71  // OverRun:   Offset == 0, Length < BlockSize
     72  // Middle:    Offset is block aligned, Length is multiple of block size
     73  //
     74  UINT32                          Signature;
     75  LIST_ENTRY                      Link;
     76  BOOLEAN                         Write;
     77  UINT64                          Lba;
     78  UINT32                          Offset;
     79  UINTN                           Length;
     80  UINT8                           *WorkingBuffer; /// < NULL indicates using "Buffer" directly
     81  UINT8                           *Buffer;
     82  BOOLEAN                         Blocking;
     83
     84  //
     85  // Following fields are for DiskIo2
     86  //
     87  DISK_IO2_TASK                   *Task;
     88  EFI_BLOCK_IO2_TOKEN             BlockIo2Token;
     89} DISK_IO_SUBTASK;
    4390
    4491//
     
    190237  );
    191238
     239
     240/**
     241  Terminate outstanding asynchronous requests to a device.
     242
     243  @param This                   Indicates a pointer to the calling context.
     244
     245  @retval EFI_SUCCESS           All outstanding requests were successfully terminated.
     246  @retval EFI_DEVICE_ERROR      The device reported an error while performing the cancel
     247                                operation.
     248**/
     249EFI_STATUS
     250EFIAPI
     251DiskIo2Cancel (
     252  IN EFI_DISK_IO2_PROTOCOL *This
     253  );
     254
     255/**
     256  Reads a specified number of bytes from a device.
     257
     258  @param This                   Indicates a pointer to the calling context.
     259  @param MediaId                ID of the medium to be read.
     260  @param Offset                 The starting byte offset on the logical block I/O device to read from.
     261  @param Token                  A pointer to the token associated with the transaction.
     262                                If this field is NULL, synchronous/blocking IO is performed.
     263  @param  BufferSize            The size in bytes of Buffer. The number of bytes to read from the device.
     264  @param  Buffer                A pointer to the destination buffer for the data.
     265                                The caller is responsible either having implicit or explicit ownership of the buffer.
     266
     267  @retval EFI_SUCCESS           If Event is NULL (blocking I/O): The data was read correctly from the device.
     268                                If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
     269                                                                         Event will be signaled upon completion.
     270  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
     271  @retval EFI_NO_MEDIA          There is no medium in the device.
     272  @retval EFI_MEDIA_CHNAGED     The MediaId is not for the current medium.
     273  @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not valid for the device.
     274  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
     275
     276**/
     277EFI_STATUS
     278EFIAPI
     279DiskIo2ReadDiskEx (
     280  IN EFI_DISK_IO2_PROTOCOL        *This,
     281  IN UINT32                       MediaId,
     282  IN UINT64                       Offset,
     283  IN OUT EFI_DISK_IO2_TOKEN       *Token,
     284  IN UINTN                        BufferSize,
     285  OUT VOID                        *Buffer
     286  );
     287
     288/**
     289  Writes a specified number of bytes to a device.
     290
     291  @param This        Indicates a pointer to the calling context.
     292  @param MediaId     ID of the medium to be written.
     293  @param Offset      The starting byte offset on the logical block I/O device to write to.
     294  @param Token       A pointer to the token associated with the transaction.
     295                     If this field is NULL, synchronous/blocking IO is performed.
     296  @param BufferSize  The size in bytes of Buffer. The number of bytes to write to the device.
     297  @param Buffer      A pointer to the buffer containing the data to be written.
     298
     299  @retval EFI_SUCCESS           If Event is NULL (blocking I/O): The data was written correctly to the device.
     300                                If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
     301                                                                         Event will be signaled upon completion.
     302  @retval EFI_WRITE_PROTECTED   The device cannot be written to.
     303  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write operation.
     304  @retval EFI_NO_MEDIA          There is no medium in the device.
     305  @retval EFI_MEDIA_CHNAGED     The MediaId is not for the current medium.
     306  @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not valid for the device.
     307  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
     308
     309**/
     310EFI_STATUS
     311EFIAPI
     312DiskIo2WriteDiskEx (
     313  IN EFI_DISK_IO2_PROTOCOL        *This,
     314  IN UINT32                       MediaId,
     315  IN UINT64                       Offset,
     316  IN EFI_DISK_IO2_TOKEN           *Token,
     317  IN UINTN                        BufferSize,
     318  IN VOID                         *Buffer
     319  );
     320
     321/**
     322  Flushes all modified data to the physical device.
     323
     324  @param This        Indicates a pointer to the calling context.
     325  @param Token       A pointer to the token associated with the transaction.
     326                     If this field is NULL, synchronous/blocking IO is performed.
     327
     328  @retval EFI_SUCCESS           If Event is NULL (blocking I/O): The data was flushed successfully to the device.
     329                                If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
     330                                                                         Event will be signaled upon completion.
     331  @retval EFI_WRITE_PROTECTED   The device cannot be written to.
     332  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write operation.
     333  @retval EFI_NO_MEDIA          There is no medium in the device.
     334  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
     335**/
     336EFI_STATUS
     337EFIAPI
     338DiskIo2FlushDiskEx (
     339  IN EFI_DISK_IO2_PROTOCOL        *This,
     340  IN OUT EFI_DISK_IO2_TOKEN       *Token
     341  );
     342
    192343//
    193344// EFI Component Name Functions
  • trunk/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf

    r48674 r58459  
    99#  code utilize the Disk I/O protocol.
    1010
    11 #  Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
     11#  Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
    1212#  This program and the accompanying materials
    1313#  are licensed and made available under the terms and conditions of the BSD License
     
    2323  INF_VERSION                    = 0x00010005
    2424  BASE_NAME                      = DiskIoDxe
     25  MODULE_UNI_FILE                = DiskIoDxe.uni
    2526  FILE_GUID                      = 6B38F7B4-AD98-40e9-9093-ACA2B5A253C4
    2627  MODULE_TYPE                    = UEFI_DRIVER
     
    4647[Packages]
    4748  MdePkg/MdePkg.dec
    48 
     49  MdeModulePkg/MdeModulePkg.dec
    4950
    5051[LibraryClasses]
     
    5657  UefiDriverEntryPoint
    5758  DebugLib
    58 
     59  PcdLib
    5960
    6061[Protocols]
    6162  gEfiDiskIoProtocolGuid                        ## BY_START
     63  gEfiDiskIo2ProtocolGuid                       ## BY_START
    6264  gEfiBlockIoProtocolGuid                       ## TO_START
     65  gEfiBlockIo2ProtocolGuid                      ## TO_START
    6366
     67[Pcd]
     68  gEfiMdeModulePkgTokenSpaceGuid.PcdDiskIoDataBufferBlockNum    ## SOMETIMES_CONSUMES
     69
     70[UserExtensions.TianoCore."ExtraFiles"]
     71  DiskIoDxeExtra.uni
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette