From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001
From: Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com>
Date: Tue, 10 Oct 2023 14:33:42 +0000
Subject: Add submodule dependency files

Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
---
 .../MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c | 1262 ++++++++++++++++++++
 1 file changed, 1262 insertions(+)
 create mode 100644 roms/edk2/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c

(limited to 'roms/edk2/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c')

diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c b/roms/edk2/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c
new file mode 100644
index 000000000..e19466bd2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c
@@ -0,0 +1,1262 @@
+/** @file
+  DiskIo driver that lays on every BlockIo protocol in the system.
+  DiskIo converts a block oriented device to a byte oriented device.
+
+  Disk access may have to handle unaligned request about sector boundaries.
+  There are three cases:
+    UnderRun - The first byte is not on a sector boundary or the read request is
+               less than a sector in length.
+    Aligned  - A read of N contiguous sectors.
+    OverRun  - The last byte is not on a sector boundary.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DiskIo.h"
+
+//
+// Driver binding protocol implementation for DiskIo driver.
+//
+EFI_DRIVER_BINDING_PROTOCOL gDiskIoDriverBinding = {
+  DiskIoDriverBindingSupported,
+  DiskIoDriverBindingStart,
+  DiskIoDriverBindingStop,
+  0xa,
+  NULL,
+  NULL
+};
+
+//
+// Template for DiskIo private data structure.
+// The pointer to BlockIo protocol interface is assigned dynamically.
+//
+DISK_IO_PRIVATE_DATA        gDiskIoPrivateDataTemplate = {
+  DISK_IO_PRIVATE_DATA_SIGNATURE,
+  {
+    EFI_DISK_IO_PROTOCOL_REVISION,
+    DiskIoReadDisk,
+    DiskIoWriteDisk
+  },
+  {
+    EFI_DISK_IO2_PROTOCOL_REVISION,
+    DiskIo2Cancel,
+    DiskIo2ReadDiskEx,
+    DiskIo2WriteDiskEx,
+    DiskIo2FlushDiskEx
+  }
+};
+
+/**
+  Test to see if this driver supports ControllerHandle.
+
+  @param  This                Protocol instance pointer.
+  @param  ControllerHandle    Handle of device to test
+  @param  RemainingDevicePath Optional parameter use to pick a specific child
+                              device to start.
+
+  @retval EFI_SUCCESS         This driver supports this device
+  @retval EFI_ALREADY_STARTED This driver is already running on this device
+  @retval other               This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIoDriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
+  )
+{
+  EFI_STATUS            Status;
+  EFI_BLOCK_IO_PROTOCOL *BlockIo;
+
+  //
+  // Open the IO Abstraction(s) needed to perform the supported test.
+  //
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiBlockIoProtocolGuid,
+                  (VOID **) &BlockIo,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Close the I/O Abstraction(s) used to perform the supported test.
+  //
+  gBS->CloseProtocol (
+         ControllerHandle,
+         &gEfiBlockIoProtocolGuid,
+         This->DriverBindingHandle,
+         ControllerHandle
+         );
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Start this driver on ControllerHandle by opening a Block IO protocol and
+  installing a Disk IO protocol on ControllerHandle.
+
+  @param  This                 Protocol instance pointer.
+  @param  ControllerHandle     Handle of device to bind driver to
+  @param  RemainingDevicePath  Optional parameter use to pick a specific child
+                               device to start.
+
+  @retval EFI_SUCCESS          This driver is added to ControllerHandle
+  @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle
+  @retval other                This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIoDriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
+  )
+{
+  EFI_STATUS            Status;
+  DISK_IO_PRIVATE_DATA  *Instance;
+  EFI_TPL               OldTpl;
+
+  Instance = NULL;
+
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+  //
+  // Connect to the Block IO and Block IO2 interface on ControllerHandle.
+  //
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiBlockIoProtocolGuid,
+                  (VOID **) &gDiskIoPrivateDataTemplate.BlockIo,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (EFI_ERROR (Status)) {
+    goto ErrorExit1;
+  }
+
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiBlockIo2ProtocolGuid,
+                  (VOID **) &gDiskIoPrivateDataTemplate.BlockIo2,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (EFI_ERROR (Status)) {
+    gDiskIoPrivateDataTemplate.BlockIo2 = NULL;
+  }
+
+  //
+  // Initialize the Disk IO device instance.
+  //
+  Instance = AllocateCopyPool (sizeof (DISK_IO_PRIVATE_DATA), &gDiskIoPrivateDataTemplate);
+  if (Instance == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto ErrorExit;
+  }
+
+  //
+  // The BlockSize and IoAlign of BlockIo and BlockIo2 should equal.
+  //
+  ASSERT ((Instance->BlockIo2 == NULL) ||
+          ((Instance->BlockIo->Media->IoAlign == Instance->BlockIo2->Media->IoAlign) &&
+           (Instance->BlockIo->Media->BlockSize == Instance->BlockIo2->Media->BlockSize)
+          ));
+
+  InitializeListHead (&Instance->TaskQueue);
+  EfiInitializeLock (&Instance->TaskQueueLock, TPL_NOTIFY);
+  Instance->SharedWorkingBuffer = AllocateAlignedPages (
+                                    EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum) * Instance->BlockIo->Media->BlockSize),
+                                    Instance->BlockIo->Media->IoAlign
+                                    );
+  if (Instance->SharedWorkingBuffer == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto ErrorExit;
+  }
+
+  //
+  // Install protocol interfaces for the Disk IO device.
+  //
+  if (Instance->BlockIo2 != NULL) {
+    Status = gBS->InstallMultipleProtocolInterfaces (
+                    &ControllerHandle,
+                    &gEfiDiskIoProtocolGuid,  &Instance->DiskIo,
+                    &gEfiDiskIo2ProtocolGuid, &Instance->DiskIo2,
+                    NULL
+                    );
+  } else {
+    Status = gBS->InstallMultipleProtocolInterfaces (
+                    &ControllerHandle,
+                    &gEfiDiskIoProtocolGuid,  &Instance->DiskIo,
+                    NULL
+                    );
+  }
+
+ErrorExit:
+  if (EFI_ERROR (Status)) {
+    if (Instance != NULL && Instance->SharedWorkingBuffer != NULL) {
+      FreeAlignedPages (
+        Instance->SharedWorkingBuffer,
+        EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum) * Instance->BlockIo->Media->BlockSize)
+        );
+    }
+
+    if (Instance != NULL) {
+      FreePool (Instance);
+    }
+
+    gBS->CloseProtocol (
+           ControllerHandle,
+           &gEfiBlockIoProtocolGuid,
+           This->DriverBindingHandle,
+           ControllerHandle
+           );
+  }
+
+ErrorExit1:
+  gBS->RestoreTPL (OldTpl);
+  return Status;
+}
+
+/**
+  Stop this driver on ControllerHandle by removing Disk IO protocol and closing
+  the Block IO protocol on ControllerHandle.
+
+  @param  This              Protocol instance pointer.
+  @param  ControllerHandle  Handle of device to stop driver on
+  @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
+                            children is zero stop the entire bus driver.
+  @param  ChildHandleBuffer List of Child Handles to Stop.
+
+  @retval EFI_SUCCESS       This driver is removed ControllerHandle
+  @retval other             This driver was not removed from this device
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIoDriverBindingStop (
+  IN  EFI_DRIVER_BINDING_PROTOCOL    *This,
+  IN  EFI_HANDLE                     ControllerHandle,
+  IN  UINTN                          NumberOfChildren,
+  IN  EFI_HANDLE                     *ChildHandleBuffer
+  )
+{
+  EFI_STATUS            Status;
+  EFI_DISK_IO_PROTOCOL  *DiskIo;
+  EFI_DISK_IO2_PROTOCOL *DiskIo2;
+  DISK_IO_PRIVATE_DATA  *Instance;
+  BOOLEAN               AllTaskDone;
+
+  //
+  // Get our context back.
+  //
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiDiskIoProtocolGuid,
+                  (VOID **) &DiskIo,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiDiskIo2ProtocolGuid,
+                  (VOID **) &DiskIo2,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    DiskIo2 = NULL;
+  }
+
+  Instance = DISK_IO_PRIVATE_DATA_FROM_DISK_IO (DiskIo);
+
+  if (DiskIo2 != NULL) {
+    //
+    // Call BlockIo2::Reset() to terminate any in-flight non-blocking I/O requests
+    //
+    ASSERT (Instance->BlockIo2 != NULL);
+    Status = Instance->BlockIo2->Reset (Instance->BlockIo2, FALSE);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+    Status = gBS->UninstallMultipleProtocolInterfaces (
+                    ControllerHandle,
+                    &gEfiDiskIoProtocolGuid,  &Instance->DiskIo,
+                    &gEfiDiskIo2ProtocolGuid, &Instance->DiskIo2,
+                    NULL
+                    );
+  } else {
+    Status = gBS->UninstallMultipleProtocolInterfaces (
+                    ControllerHandle,
+                    &gEfiDiskIoProtocolGuid,  &Instance->DiskIo,
+                    NULL
+                    );
+  }
+  if (!EFI_ERROR (Status)) {
+
+    do {
+      EfiAcquireLock (&Instance->TaskQueueLock);
+      AllTaskDone = IsListEmpty (&Instance->TaskQueue);
+      EfiReleaseLock (&Instance->TaskQueueLock);
+    } while (!AllTaskDone);
+
+    FreeAlignedPages (
+      Instance->SharedWorkingBuffer,
+      EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum) * Instance->BlockIo->Media->BlockSize)
+      );
+
+    Status = gBS->CloseProtocol (
+                    ControllerHandle,
+                    &gEfiBlockIoProtocolGuid,
+                    This->DriverBindingHandle,
+                    ControllerHandle
+                    );
+    ASSERT_EFI_ERROR (Status);
+    if (DiskIo2 != NULL) {
+      Status = gBS->CloseProtocol (
+                      ControllerHandle,
+                      &gEfiBlockIo2ProtocolGuid,
+                      This->DriverBindingHandle,
+                      ControllerHandle
+                      );
+      ASSERT_EFI_ERROR (Status);
+    }
+
+    FreePool (Instance);
+  }
+
+  return Status;
+}
+
+
+/**
+  Destroy the sub task.
+
+  @param Instance     Pointer to the DISK_IO_PRIVATE_DATA.
+  @param Subtask      Subtask.
+
+  @return LIST_ENTRY *  Pointer to the next link of subtask.
+**/
+LIST_ENTRY *
+DiskIoDestroySubtask (
+  IN DISK_IO_PRIVATE_DATA     *Instance,
+  IN DISK_IO_SUBTASK          *Subtask
+  )
+{
+  LIST_ENTRY               *Link;
+
+  if (Subtask->Task != NULL) {
+    EfiAcquireLock (&Subtask->Task->SubtasksLock);
+  }
+  Link = RemoveEntryList (&Subtask->Link);
+  if (Subtask->Task != NULL) {
+    EfiReleaseLock (&Subtask->Task->SubtasksLock);
+  }
+
+  if (!Subtask->Blocking) {
+    if (Subtask->WorkingBuffer != NULL) {
+      FreeAlignedPages (
+        Subtask->WorkingBuffer,
+        Subtask->Length < Instance->BlockIo->Media->BlockSize
+        ? EFI_SIZE_TO_PAGES (Instance->BlockIo->Media->BlockSize)
+        : EFI_SIZE_TO_PAGES (Subtask->Length)
+        );
+    }
+    if (Subtask->BlockIo2Token.Event != NULL) {
+      gBS->CloseEvent (Subtask->BlockIo2Token.Event);
+    }
+  }
+  FreePool (Subtask);
+
+  return Link;
+}
+
+/**
+  The callback for the BlockIo2 ReadBlocksEx/WriteBlocksEx.
+  @param  Event                 Event whose notification function is being invoked.
+  @param  Context               The pointer to the notification function's context,
+                                which points to the DISK_IO_SUBTASK instance.
+**/
+VOID
+EFIAPI
+DiskIo2OnReadWriteComplete (
+  IN EFI_EVENT            Event,
+  IN VOID                 *Context
+  )
+{
+  DISK_IO_SUBTASK       *Subtask;
+  DISK_IO2_TASK         *Task;
+  EFI_STATUS            TransactionStatus;
+  DISK_IO_PRIVATE_DATA  *Instance;
+
+  Subtask           = (DISK_IO_SUBTASK *) Context;
+  TransactionStatus = Subtask->BlockIo2Token.TransactionStatus;
+  Task              = Subtask->Task;
+  Instance          = Task->Instance;
+
+  ASSERT (Subtask->Signature  == DISK_IO_SUBTASK_SIGNATURE);
+  ASSERT (Instance->Signature == DISK_IO_PRIVATE_DATA_SIGNATURE);
+  ASSERT (Task->Signature     == DISK_IO2_TASK_SIGNATURE);
+
+  if ((Subtask->WorkingBuffer != NULL) && !EFI_ERROR (TransactionStatus) &&
+      (Task->Token != NULL) && !Subtask->Write
+     ) {
+    CopyMem (Subtask->Buffer, Subtask->WorkingBuffer + Subtask->Offset, Subtask->Length);
+  }
+
+  DiskIoDestroySubtask (Instance, Subtask);
+
+  if (EFI_ERROR (TransactionStatus) || IsListEmpty (&Task->Subtasks)) {
+    if (Task->Token != NULL) {
+      //
+      // Signal error status once the subtask is failed.
+      // Or signal the last status once the last subtask is finished.
+      //
+      Task->Token->TransactionStatus = TransactionStatus;
+      gBS->SignalEvent (Task->Token->Event);
+
+      //
+      // Mark token to NULL indicating the Task is a dead task.
+      //
+      Task->Token = NULL;
+    }
+  }
+}
+
+/**
+  Create the subtask.
+
+  @param Write         TRUE: Write request; FALSE: Read request.
+  @param Lba           The starting logical block address to read from on the device.
+  @param Offset        The starting byte offset to read from the LBA.
+  @param Length        The number of bytes to read from the device.
+  @param WorkingBuffer The aligned buffer to hold the data for reading or writing.
+  @param Buffer        The buffer to hold the data for reading or writing.
+  @param Blocking      TRUE: Blocking request; FALSE: Non-blocking request.
+
+  @return A pointer to the created subtask.
+**/
+DISK_IO_SUBTASK *
+DiskIoCreateSubtask (
+  IN BOOLEAN          Write,
+  IN UINT64           Lba,
+  IN UINT32           Offset,
+  IN UINTN            Length,
+  IN VOID             *WorkingBuffer,  OPTIONAL
+  IN VOID             *Buffer,
+  IN BOOLEAN          Blocking
+  )
+{
+  DISK_IO_SUBTASK       *Subtask;
+  EFI_STATUS            Status;
+
+  Subtask = AllocateZeroPool (sizeof (DISK_IO_SUBTASK));
+  if (Subtask == NULL) {
+    return NULL;
+  }
+  Subtask->Signature     = DISK_IO_SUBTASK_SIGNATURE;
+  Subtask->Write         = Write;
+  Subtask->Lba           = Lba;
+  Subtask->Offset        = Offset;
+  Subtask->Length        = Length;
+  Subtask->WorkingBuffer = WorkingBuffer;
+  Subtask->Buffer        = Buffer;
+  Subtask->Blocking      = Blocking;
+  if (!Blocking) {
+    Status = gBS->CreateEvent (
+                    EVT_NOTIFY_SIGNAL,
+                    TPL_NOTIFY,
+                    DiskIo2OnReadWriteComplete,
+                    Subtask,
+                    &Subtask->BlockIo2Token.Event
+                    );
+    if (EFI_ERROR (Status)) {
+      FreePool (Subtask);
+      return NULL;
+    }
+  }
+  DEBUG ((
+    EFI_D_BLKIO,
+    "  %c:Lba/Offset/Length/WorkingBuffer/Buffer = %016lx/%08x/%08x/%08x/%08x\n",
+    Write ? 'W': 'R', Lba, Offset, Length, WorkingBuffer, Buffer
+    ));
+
+  return Subtask;
+}
+
+/**
+  Create the subtask list.
+
+  @param Instance            Pointer to the DISK_IO_PRIVATE_DATA.
+  @param Write               TRUE: Write request; FALSE: Read request.
+  @param Offset              The starting byte offset to read from the device.
+  @param BufferSize          The size in bytes of Buffer. The number of bytes to read from the device.
+  @param Buffer              A pointer to the buffer for the data.
+  @param Blocking            TRUE: Blocking request; FALSE: Non-blocking request.
+  @param SharedWorkingBuffer The aligned buffer to hold the data for reading or writing.
+  @param Subtasks            The subtask list header.
+
+  @retval TRUE  The subtask list is created successfully.
+  @retval FALSE The subtask list is not created.
+**/
+BOOLEAN
+DiskIoCreateSubtaskList (
+  IN DISK_IO_PRIVATE_DATA  *Instance,
+  IN BOOLEAN               Write,
+  IN UINT64                Offset,
+  IN UINTN                 BufferSize,
+  IN VOID                  *Buffer,
+  IN BOOLEAN               Blocking,
+  IN VOID                  *SharedWorkingBuffer,
+  IN OUT LIST_ENTRY        *Subtasks
+  )
+{
+  UINT32                BlockSize;
+  UINT32                IoAlign;
+  UINT64                Lba;
+  UINT64                OverRunLba;
+  UINT32                UnderRun;
+  UINT32                OverRun;
+  UINT8                 *BufferPtr;
+  UINTN                 Length;
+  UINTN                 DataBufferSize;
+  DISK_IO_SUBTASK       *Subtask;
+  VOID                  *WorkingBuffer;
+  LIST_ENTRY            *Link;
+
+  DEBUG ((EFI_D_BLKIO, "DiskIo: Create subtasks for task: Offset/BufferSize/Buffer = %016lx/%08x/%08x\n", Offset, BufferSize, Buffer));
+
+  BlockSize = Instance->BlockIo->Media->BlockSize;
+  IoAlign   = Instance->BlockIo->Media->IoAlign;
+  if (IoAlign == 0) {
+    IoAlign = 1;
+  }
+
+  Lba       = DivU64x32Remainder (Offset, BlockSize, &UnderRun);
+  BufferPtr = (UINT8 *) Buffer;
+
+  //
+  // Special handling for zero BufferSize
+  //
+  if (BufferSize == 0) {
+    Subtask = DiskIoCreateSubtask (Write, Lba, UnderRun, 0, NULL, BufferPtr, Blocking);
+    if (Subtask == NULL) {
+      goto Done;
+    }
+    InsertTailList (Subtasks, &Subtask->Link);
+    return TRUE;
+  }
+
+  if (UnderRun != 0) {
+    Length = MIN (BlockSize - UnderRun, BufferSize);
+    if (Blocking) {
+      WorkingBuffer = SharedWorkingBuffer;
+    } else {
+      WorkingBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BlockSize), IoAlign);
+      if (WorkingBuffer == NULL) {
+        goto Done;
+      }
+    }
+    if (Write) {
+      //
+      // A half write operation can be splitted to a blocking block-read and half write operation
+      // This can simplify the sub task processing logic
+      //
+      Subtask = DiskIoCreateSubtask (FALSE, Lba, 0, BlockSize, NULL, WorkingBuffer, TRUE);
+      if (Subtask == NULL) {
+        goto Done;
+      }
+      InsertTailList (Subtasks, &Subtask->Link);
+    }
+
+    Subtask = DiskIoCreateSubtask (Write, Lba, UnderRun, Length, WorkingBuffer, BufferPtr, Blocking);
+    if (Subtask == NULL) {
+      goto Done;
+    }
+    InsertTailList (Subtasks, &Subtask->Link);
+
+    BufferPtr  += Length;
+    Offset     += Length;
+    BufferSize -= Length;
+    Lba ++;
+  }
+
+  OverRunLba  = Lba + DivU64x32Remainder (BufferSize, BlockSize, &OverRun);
+  BufferSize -= OverRun;
+
+  if (OverRun != 0) {
+    if (Blocking) {
+      WorkingBuffer = SharedWorkingBuffer;
+    } else {
+      WorkingBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BlockSize), IoAlign);
+      if (WorkingBuffer == NULL) {
+        goto Done;
+      }
+    }
+    if (Write) {
+      //
+      // A half write operation can be splitted to a blocking block-read and half write operation
+      // This can simplify the sub task processing logic
+      //
+      Subtask = DiskIoCreateSubtask (FALSE, OverRunLba, 0, BlockSize, NULL, WorkingBuffer, TRUE);
+      if (Subtask == NULL) {
+        goto Done;
+      }
+      InsertTailList (Subtasks, &Subtask->Link);
+    }
+
+    Subtask = DiskIoCreateSubtask (Write, OverRunLba, 0, OverRun, WorkingBuffer, BufferPtr + BufferSize, Blocking);
+    if (Subtask == NULL) {
+      goto Done;
+    }
+    InsertTailList (Subtasks, &Subtask->Link);
+  }
+
+  if (OverRunLba > Lba) {
+    //
+    // If the DiskIo maps directly to a BlockIo device do the read.
+    //
+    if (ALIGN_POINTER (BufferPtr, IoAlign) == BufferPtr) {
+      Subtask = DiskIoCreateSubtask (Write, Lba, 0, BufferSize, NULL, BufferPtr, Blocking);
+      if (Subtask == NULL) {
+        goto Done;
+      }
+      InsertTailList (Subtasks, &Subtask->Link);
+
+      BufferPtr  += BufferSize;
+      Offset     += BufferSize;
+      BufferSize -= BufferSize;
+
+    } else {
+      if (Blocking) {
+        //
+        // Use the allocated buffer instead of the original buffer
+        // to avoid alignment issue.
+        //
+        for (; Lba < OverRunLba; Lba += PcdGet32 (PcdDiskIoDataBufferBlockNum)) {
+          DataBufferSize = MIN (BufferSize, PcdGet32 (PcdDiskIoDataBufferBlockNum) * BlockSize);
+
+          Subtask = DiskIoCreateSubtask (Write, Lba, 0, DataBufferSize, SharedWorkingBuffer, BufferPtr, Blocking);
+          if (Subtask == NULL) {
+            goto Done;
+          }
+          InsertTailList (Subtasks, &Subtask->Link);
+
+          BufferPtr  += DataBufferSize;
+          Offset     += DataBufferSize;
+          BufferSize -= DataBufferSize;
+        }
+      } else {
+        WorkingBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), IoAlign);
+        if (WorkingBuffer == NULL) {
+          //
+          // If there is not enough memory, downgrade to blocking access
+          //
+          DEBUG ((EFI_D_VERBOSE, "DiskIo: No enough memory so downgrade to blocking access\n"));
+          if (!DiskIoCreateSubtaskList (Instance, Write, Offset, BufferSize, BufferPtr, TRUE, SharedWorkingBuffer, Subtasks)) {
+            goto Done;
+          }
+        } else {
+          Subtask = DiskIoCreateSubtask (Write, Lba, 0, BufferSize, WorkingBuffer, BufferPtr, Blocking);
+          if (Subtask == NULL) {
+            goto Done;
+          }
+          InsertTailList (Subtasks, &Subtask->Link);
+        }
+
+        BufferPtr  += BufferSize;
+        Offset     += BufferSize;
+        BufferSize -= BufferSize;
+      }
+    }
+  }
+
+  ASSERT (BufferSize == 0);
+
+  return TRUE;
+
+Done:
+  //
+  // Remove all the subtasks.
+  //
+  for (Link = GetFirstNode (Subtasks); !IsNull (Subtasks, Link); ) {
+    Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
+    Link = DiskIoDestroySubtask (Instance, Subtask);
+  }
+  return FALSE;
+}
+
+/**
+  Terminate outstanding asynchronous requests to a device.
+
+  @param This                   Indicates a pointer to the calling context.
+
+  @retval EFI_SUCCESS           All outstanding requests were successfully terminated.
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the cancel
+                                operation.
+**/
+EFI_STATUS
+EFIAPI
+DiskIo2Cancel (
+  IN EFI_DISK_IO2_PROTOCOL *This
+  )
+{
+  DISK_IO_PRIVATE_DATA  *Instance;
+  DISK_IO2_TASK         *Task;
+  LIST_ENTRY            *Link;
+
+  Instance = DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This);
+
+  EfiAcquireLock (&Instance->TaskQueueLock);
+
+  for (Link = GetFirstNode (&Instance->TaskQueue)
+    ; !IsNull (&Instance->TaskQueue, Link)
+    ; Link = GetNextNode (&Instance->TaskQueue, Link)
+    ) {
+    Task = CR (Link, DISK_IO2_TASK, Link, DISK_IO2_TASK_SIGNATURE);
+
+    if (Task->Token != NULL) {
+      Task->Token->TransactionStatus = EFI_ABORTED;
+      gBS->SignalEvent (Task->Token->Event);
+      //
+      // Set Token to NULL so that the further BlockIo2 responses will be ignored
+      //
+      Task->Token = NULL;
+    }
+  }
+
+  EfiReleaseLock (&Instance->TaskQueueLock);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Remove the completed tasks from Instance->TaskQueue. Completed tasks are those who don't have any subtasks.
+
+  @param Instance    Pointer to the DISK_IO_PRIVATE_DATA.
+
+  @retval TRUE       The Instance->TaskQueue is empty after the completed tasks are removed.
+  @retval FALSE      The Instance->TaskQueue is not empty after the completed tasks are removed.
+**/
+BOOLEAN
+DiskIo2RemoveCompletedTask (
+  IN DISK_IO_PRIVATE_DATA     *Instance
+  )
+{
+  BOOLEAN                     QueueEmpty;
+  LIST_ENTRY                  *Link;
+  DISK_IO2_TASK               *Task;
+
+  QueueEmpty = TRUE;
+
+  EfiAcquireLock (&Instance->TaskQueueLock);
+  for (Link = GetFirstNode (&Instance->TaskQueue); !IsNull (&Instance->TaskQueue, Link); ) {
+    Task = CR (Link, DISK_IO2_TASK, Link, DISK_IO2_TASK_SIGNATURE);
+    if (IsListEmpty (&Task->Subtasks)) {
+      Link = RemoveEntryList (&Task->Link);
+      ASSERT (Task->Token == NULL);
+      FreePool (Task);
+    } else {
+      Link = GetNextNode (&Instance->TaskQueue, Link);
+      QueueEmpty = FALSE;
+    }
+  }
+  EfiReleaseLock (&Instance->TaskQueueLock);
+
+  return QueueEmpty;
+}
+
+/**
+  Common routine to access the disk.
+
+  @param Instance    Pointer to the DISK_IO_PRIVATE_DATA.
+  @param Write       TRUE: Write operation; FALSE: Read operation.
+  @param MediaId     ID of the medium to access.
+  @param Offset      The starting byte offset on the logical block I/O device to access.
+  @param Token       A pointer to the token associated with the transaction.
+                     If this field is NULL, synchronous/blocking IO is performed.
+  @param  BufferSize            The size in bytes of Buffer. The number of bytes to read from the device.
+  @param  Buffer                A pointer to the destination buffer for the data.
+                                The caller is responsible either having implicit or explicit ownership of the buffer.
+**/
+EFI_STATUS
+DiskIo2ReadWriteDisk (
+  IN DISK_IO_PRIVATE_DATA     *Instance,
+  IN BOOLEAN                  Write,
+  IN UINT32                   MediaId,
+  IN UINT64                   Offset,
+  IN EFI_DISK_IO2_TOKEN       *Token,
+  IN UINTN                    BufferSize,
+  IN UINT8                    *Buffer
+  )
+{
+  EFI_STATUS             Status;
+  EFI_BLOCK_IO_PROTOCOL  *BlockIo;
+  EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
+  EFI_BLOCK_IO_MEDIA     *Media;
+  LIST_ENTRY             *Link;
+  LIST_ENTRY             *NextLink;
+  LIST_ENTRY             Subtasks;
+  DISK_IO_SUBTASK        *Subtask;
+  DISK_IO2_TASK          *Task;
+  EFI_TPL                OldTpl;
+  BOOLEAN                Blocking;
+  BOOLEAN                SubtaskBlocking;
+  LIST_ENTRY             *SubtasksPtr;
+
+  Task      = NULL;
+  BlockIo   = Instance->BlockIo;
+  BlockIo2  = Instance->BlockIo2;
+  Media     = BlockIo->Media;
+  Status    = EFI_SUCCESS;
+  Blocking  = (BOOLEAN) ((Token == NULL) || (Token->Event == NULL));
+
+  if (Blocking) {
+    //
+    // Wait till pending async task is completed.
+    //
+    while (!DiskIo2RemoveCompletedTask (Instance));
+
+    SubtasksPtr = &Subtasks;
+  } else {
+    DiskIo2RemoveCompletedTask (Instance);
+    Task = AllocatePool (sizeof (DISK_IO2_TASK));
+    if (Task == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    EfiAcquireLock (&Instance->TaskQueueLock);
+    InsertTailList (&Instance->TaskQueue, &Task->Link);
+    EfiReleaseLock (&Instance->TaskQueueLock);
+
+    Task->Signature = DISK_IO2_TASK_SIGNATURE;
+    Task->Instance  = Instance;
+    Task->Token     = Token;
+    EfiInitializeLock (&Task->SubtasksLock, TPL_NOTIFY);
+
+    SubtasksPtr = &Task->Subtasks;
+  }
+
+  InitializeListHead (SubtasksPtr);
+  if (!DiskIoCreateSubtaskList (Instance, Write, Offset, BufferSize, Buffer, Blocking, Instance->SharedWorkingBuffer, SubtasksPtr)) {
+    if (Task != NULL) {
+      FreePool (Task);
+    }
+    return EFI_OUT_OF_RESOURCES;
+  }
+  ASSERT (!IsListEmpty (SubtasksPtr));
+
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+  for ( Link = GetFirstNode (SubtasksPtr), NextLink = GetNextNode (SubtasksPtr, Link)
+      ; !IsNull (SubtasksPtr, Link)
+      ; Link = NextLink, NextLink = GetNextNode (SubtasksPtr, NextLink)
+      ) {
+    Subtask         = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
+    Subtask->Task   = Task;
+    SubtaskBlocking = Subtask->Blocking;
+
+    ASSERT ((Subtask->Length % Media->BlockSize == 0) || (Subtask->Length < Media->BlockSize));
+
+    if (Subtask->Write) {
+      //
+      // Write
+      //
+      if (Subtask->WorkingBuffer != NULL) {
+        //
+        // A sub task before this one should be a block read operation, causing the WorkingBuffer filled with the entire one block data.
+        //
+        CopyMem (Subtask->WorkingBuffer + Subtask->Offset, Subtask->Buffer, Subtask->Length);
+      }
+
+      if (SubtaskBlocking) {
+        Status = BlockIo->WriteBlocks (
+                            BlockIo,
+                            MediaId,
+                            Subtask->Lba,
+                            (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
+                            (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
+                            );
+      } else {
+        Status = BlockIo2->WriteBlocksEx (
+                             BlockIo2,
+                             MediaId,
+                             Subtask->Lba,
+                             &Subtask->BlockIo2Token,
+                             (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
+                             (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
+                             );
+      }
+
+    } else {
+      //
+      // Read
+      //
+      if (SubtaskBlocking) {
+        Status = BlockIo->ReadBlocks (
+                            BlockIo,
+                            MediaId,
+                            Subtask->Lba,
+                            (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
+                            (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
+                            );
+        if (!EFI_ERROR (Status) && (Subtask->WorkingBuffer != NULL)) {
+          CopyMem (Subtask->Buffer, Subtask->WorkingBuffer + Subtask->Offset, Subtask->Length);
+        }
+      } else {
+        Status = BlockIo2->ReadBlocksEx (
+                             BlockIo2,
+                             MediaId,
+                             Subtask->Lba,
+                             &Subtask->BlockIo2Token,
+                             (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
+                             (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
+                             );
+      }
+    }
+
+    if (SubtaskBlocking || EFI_ERROR (Status)) {
+      //
+      // Make sure the subtask list only contains non-blocking subtasks.
+      // Remove failed non-blocking subtasks as well because the callback won't be called.
+      //
+      DiskIoDestroySubtask (Instance, Subtask);
+    }
+
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+  }
+
+  gBS->RaiseTPL (TPL_NOTIFY);
+
+  //
+  // 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.
+  //
+  if (EFI_ERROR (Status)) {
+    while (!IsNull (SubtasksPtr, NextLink)) {
+      Subtask = CR (NextLink, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
+      NextLink = DiskIoDestroySubtask (Instance, Subtask);
+    }
+  }
+
+  //
+  // It's possible that the non-blocking subtasks finish before raising TPL to NOTIFY,
+  // so the subtasks list might be empty at this point.
+  //
+  if (!Blocking && IsListEmpty (SubtasksPtr)) {
+    EfiAcquireLock (&Instance->TaskQueueLock);
+    RemoveEntryList (&Task->Link);
+    EfiReleaseLock (&Instance->TaskQueueLock);
+
+    if (!EFI_ERROR (Status) && (Task->Token != NULL)) {
+      //
+      // Task->Token should be set to NULL by the DiskIo2OnReadWriteComplete
+      // It it's not, that means the non-blocking request was downgraded to blocking request.
+      //
+      DEBUG ((EFI_D_VERBOSE, "DiskIo: Non-blocking request was downgraded to blocking request, signal event directly.\n"));
+      Task->Token->TransactionStatus = Status;
+      gBS->SignalEvent (Task->Token->Event);
+    }
+
+    FreePool (Task);
+  }
+
+  gBS->RestoreTPL (OldTpl);
+
+  return Status;
+}
+
+/**
+  Reads a specified number of bytes from a device.
+
+  @param This                   Indicates a pointer to the calling context.
+  @param MediaId                ID of the medium to be read.
+  @param Offset                 The starting byte offset on the logical block I/O device to read from.
+  @param Token                  A pointer to the token associated with the transaction.
+                                If this field is NULL, synchronous/blocking IO is performed.
+  @param  BufferSize            The size in bytes of Buffer. The number of bytes to read from the device.
+  @param  Buffer                A pointer to the destination buffer for the data.
+                                The caller is responsible either having implicit or explicit ownership of the buffer.
+
+  @retval EFI_SUCCESS           If Event is NULL (blocking I/O): The data was read correctly from the device.
+                                If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
+                                                                         Event will be signaled upon completion.
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
+  @retval EFI_NO_MEDIA          There is no medium in the device.
+  @retval EFI_MEDIA_CHNAGED     The MediaId is not for the current medium.
+  @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not valid for the device.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIo2ReadDiskEx (
+  IN EFI_DISK_IO2_PROTOCOL        *This,
+  IN UINT32                       MediaId,
+  IN UINT64                       Offset,
+  IN OUT EFI_DISK_IO2_TOKEN       *Token,
+  IN UINTN                        BufferSize,
+  OUT VOID                        *Buffer
+  )
+{
+  return DiskIo2ReadWriteDisk (
+           DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This),
+           FALSE, MediaId, Offset, Token, BufferSize, (UINT8 *) Buffer
+           );
+}
+
+/**
+  Writes a specified number of bytes to a device.
+
+  @param This        Indicates a pointer to the calling context.
+  @param MediaId     ID of the medium to be written.
+  @param Offset      The starting byte offset on the logical block I/O device to write to.
+  @param Token       A pointer to the token associated with the transaction.
+                     If this field is NULL, synchronous/blocking IO is performed.
+  @param BufferSize  The size in bytes of Buffer. The number of bytes to write to the device.
+  @param Buffer      A pointer to the buffer containing the data to be written.
+
+  @retval EFI_SUCCESS           If Event is NULL (blocking I/O): The data was written correctly to the device.
+                                If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
+                                                                         Event will be signaled upon completion.
+  @retval EFI_WRITE_PROTECTED   The device cannot be written to.
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write operation.
+  @retval EFI_NO_MEDIA          There is no medium in the device.
+  @retval EFI_MEDIA_CHNAGED     The MediaId is not for the current medium.
+  @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not valid for the device.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIo2WriteDiskEx (
+  IN EFI_DISK_IO2_PROTOCOL        *This,
+  IN UINT32                       MediaId,
+  IN UINT64                       Offset,
+  IN OUT EFI_DISK_IO2_TOKEN       *Token,
+  IN UINTN                        BufferSize,
+  IN VOID                         *Buffer
+  )
+{
+  return DiskIo2ReadWriteDisk (
+           DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This),
+           TRUE, MediaId, Offset, Token, BufferSize, (UINT8 *) Buffer
+           );
+}
+
+/**
+  The callback for the BlockIo2 FlushBlocksEx.
+  @param  Event                 Event whose notification function is being invoked.
+  @param  Context               The pointer to the notification function's context,
+                                which points to the DISK_IO2_FLUSH_TASK instance.
+**/
+VOID
+EFIAPI
+DiskIo2OnFlushComplete (
+  IN EFI_EVENT                 Event,
+  IN VOID                      *Context
+  )
+{
+  DISK_IO2_FLUSH_TASK             *Task;
+
+  gBS->CloseEvent (Event);
+
+  Task = (DISK_IO2_FLUSH_TASK *) Context;
+  ASSERT (Task->Signature == DISK_IO2_FLUSH_TASK_SIGNATURE);
+  Task->Token->TransactionStatus = Task->BlockIo2Token.TransactionStatus;
+  gBS->SignalEvent (Task->Token->Event);
+
+  FreePool (Task);
+}
+
+/**
+  Flushes all modified data to the physical device.
+
+  @param This        Indicates a pointer to the calling context.
+  @param Token       A pointer to the token associated with the transaction.
+                     If this field is NULL, synchronous/blocking IO is performed.
+
+  @retval EFI_SUCCESS           If Event is NULL (blocking I/O): The data was flushed successfully to the device.
+                                If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
+                                                                         Event will be signaled upon completion.
+  @retval EFI_WRITE_PROTECTED   The device cannot be written to.
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write operation.
+  @retval EFI_NO_MEDIA          There is no medium in the device.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+DiskIo2FlushDiskEx (
+  IN EFI_DISK_IO2_PROTOCOL        *This,
+  IN OUT EFI_DISK_IO2_TOKEN       *Token
+  )
+{
+  EFI_STATUS                      Status;
+  DISK_IO2_FLUSH_TASK             *Task;
+  DISK_IO_PRIVATE_DATA            *Private;
+
+  Private = DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This);
+
+  if ((Token != NULL) && (Token->Event != NULL)) {
+    Task = AllocatePool (sizeof (DISK_IO2_FLUSH_TASK));
+    if (Task == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    Status = gBS->CreateEvent (
+                    EVT_NOTIFY_SIGNAL,
+                    TPL_CALLBACK,
+                    DiskIo2OnFlushComplete,
+                    Task,
+                    &Task->BlockIo2Token.Event
+                    );
+    if (EFI_ERROR (Status)) {
+      FreePool (Task);
+      return Status;
+    }
+    Task->Signature = DISK_IO2_FLUSH_TASK_SIGNATURE;
+    Task->Token     = Token;
+    Status = Private->BlockIo2->FlushBlocksEx (Private->BlockIo2, &Task->BlockIo2Token);
+    if (EFI_ERROR (Status)) {
+      gBS->CloseEvent (Task->BlockIo2Token.Event);
+      FreePool (Task);
+    }
+  } else {
+    Status = Private->BlockIo2->FlushBlocksEx (Private->BlockIo2, NULL);
+  }
+
+  return Status;
+}
+
+/**
+  Read BufferSize bytes from Offset into Buffer.
+  Reads may support reads that are not aligned on
+  sector boundaries. There are three cases:
+    UnderRun - The first byte is not on a sector boundary or the read request is
+               less than a sector in length.
+    Aligned  - A read of N contiguous sectors.
+    OverRun  - The last byte is not on a sector boundary.
+
+  @param  This                  Protocol instance pointer.
+  @param  MediaId               Id of the media, changes every time the media is replaced.
+  @param  Offset                The starting byte offset to read from
+  @param  BufferSize            Size of Buffer
+  @param  Buffer                Buffer containing read data
+
+  @retval EFI_SUCCESS           The data was read correctly from the device.
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.
+  @retval EFI_NO_MEDIA          There is no media in the device.
+  @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.
+  @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
+                                valid for the device.
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIoReadDisk (
+  IN EFI_DISK_IO_PROTOCOL  *This,
+  IN UINT32                MediaId,
+  IN UINT64                Offset,
+  IN UINTN                 BufferSize,
+  OUT VOID                 *Buffer
+  )
+{
+  return DiskIo2ReadWriteDisk (
+           DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This),
+           FALSE, MediaId, Offset, NULL, BufferSize, (UINT8 *) Buffer
+           );
+}
+
+
+/**
+  Writes BufferSize bytes from Buffer into Offset.
+  Writes may require a read modify write to support writes that are not
+  aligned on sector boundaries. There are three cases:
+    UnderRun - The first byte is not on a sector boundary or the write request
+               is less than a sector in length. Read modify write is required.
+    Aligned  - A write of N contiguous sectors.
+    OverRun  - The last byte is not on a sector boundary. Read modified write
+               required.
+
+  @param  This       Protocol instance pointer.
+  @param  MediaId    Id of the media, changes every time the media is replaced.
+  @param  Offset     The starting byte offset to read from
+  @param  BufferSize Size of Buffer
+  @param  Buffer     Buffer containing read data
+
+  @retval EFI_SUCCESS           The data was written correctly to the device.
+  @retval EFI_WRITE_PROTECTED   The device can not be written to.
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
+  @retval EFI_NO_MEDIA          There is no media in the device.
+  @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.
+  @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not
+                                 valid for the device.
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIoWriteDisk (
+  IN EFI_DISK_IO_PROTOCOL  *This,
+  IN UINT32                MediaId,
+  IN UINT64                Offset,
+  IN UINTN                 BufferSize,
+  IN VOID                  *Buffer
+  )
+{
+  return DiskIo2ReadWriteDisk (
+           DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This),
+           TRUE, MediaId, Offset, NULL, BufferSize, (UINT8 *) Buffer
+           );
+}
+
+/**
+  The user Entry Point for module DiskIo. The user code starts with this function.
+
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.
+  @param[in] SystemTable    A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS       The entry point is executed successfully.
+  @retval other             Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeDiskIo (
+  IN EFI_HANDLE           ImageHandle,
+  IN EFI_SYSTEM_TABLE     *SystemTable
+  )
+{
+  EFI_STATUS              Status;
+
+  //
+  // Install driver model protocol(s).
+  //
+  Status = EfiLibInstallDriverBindingComponentName2 (
+             ImageHandle,
+             SystemTable,
+             &gDiskIoDriverBinding,
+             ImageHandle,
+             &gDiskIoComponentName,
+             &gDiskIoComponentName2
+             );
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
-- 
cgit