Home | History | Annotate | Download | only in DiskIoDxe
      1 /** @file
      2   DiskIo driver that lays on every BlockIo protocol in the system.
      3   DiskIo converts a block oriented device to a byte oriented device.
      4 
      5   Disk access may have to handle unaligned request about sector boundaries.
      6   There are three cases:
      7     UnderRun - The first byte is not on a sector boundary or the read request is
      8                less than a sector in length.
      9     Aligned  - A read of N contiguous sectors.
     10     OverRun  - The last byte is not on a sector boundary.
     11 
     12 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
     13 This program and the accompanying materials
     14 are licensed and made available under the terms and conditions of the BSD License
     15 which accompanies this distribution.  The full text of the license may be found at
     16 http://opensource.org/licenses/bsd-license.php
     17 
     18 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     19 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     20 
     21 **/
     22 
     23 #include "DiskIo.h"
     24 
     25 //
     26 // Driver binding protocol implementation for DiskIo driver.
     27 //
     28 EFI_DRIVER_BINDING_PROTOCOL gDiskIoDriverBinding = {
     29   DiskIoDriverBindingSupported,
     30   DiskIoDriverBindingStart,
     31   DiskIoDriverBindingStop,
     32   0xa,
     33   NULL,
     34   NULL
     35 };
     36 
     37 //
     38 // Template for DiskIo private data structure.
     39 // The pointer to BlockIo protocol interface is assigned dynamically.
     40 //
     41 DISK_IO_PRIVATE_DATA        gDiskIoPrivateDataTemplate = {
     42   DISK_IO_PRIVATE_DATA_SIGNATURE,
     43   {
     44     EFI_DISK_IO_PROTOCOL_REVISION,
     45     DiskIoReadDisk,
     46     DiskIoWriteDisk
     47   },
     48   {
     49     EFI_DISK_IO2_PROTOCOL_REVISION,
     50     DiskIo2Cancel,
     51     DiskIo2ReadDiskEx,
     52     DiskIo2WriteDiskEx,
     53     DiskIo2FlushDiskEx
     54   }
     55 };
     56 
     57 /**
     58   Test to see if this driver supports ControllerHandle.
     59 
     60   @param  This                Protocol instance pointer.
     61   @param  ControllerHandle    Handle of device to test
     62   @param  RemainingDevicePath Optional parameter use to pick a specific child
     63                               device to start.
     64 
     65   @retval EFI_SUCCESS         This driver supports this device
     66   @retval EFI_ALREADY_STARTED This driver is already running on this device
     67   @retval other               This driver does not support this device
     68 
     69 **/
     70 EFI_STATUS
     71 EFIAPI
     72 DiskIoDriverBindingSupported (
     73   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
     74   IN EFI_HANDLE                   ControllerHandle,
     75   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
     76   )
     77 {
     78   EFI_STATUS            Status;
     79   EFI_BLOCK_IO_PROTOCOL *BlockIo;
     80 
     81   //
     82   // Open the IO Abstraction(s) needed to perform the supported test.
     83   //
     84   Status = gBS->OpenProtocol (
     85                   ControllerHandle,
     86                   &gEfiBlockIoProtocolGuid,
     87                   (VOID **) &BlockIo,
     88                   This->DriverBindingHandle,
     89                   ControllerHandle,
     90                   EFI_OPEN_PROTOCOL_BY_DRIVER
     91                   );
     92   if (EFI_ERROR (Status)) {
     93     return Status;
     94   }
     95 
     96   //
     97   // Close the I/O Abstraction(s) used to perform the supported test.
     98   //
     99   gBS->CloseProtocol (
    100          ControllerHandle,
    101          &gEfiBlockIoProtocolGuid,
    102          This->DriverBindingHandle,
    103          ControllerHandle
    104          );
    105   return EFI_SUCCESS;
    106 }
    107 
    108 
    109 /**
    110   Start this driver on ControllerHandle by opening a Block IO protocol and
    111   installing a Disk IO protocol on ControllerHandle.
    112 
    113   @param  This                 Protocol instance pointer.
    114   @param  ControllerHandle     Handle of device to bind driver to
    115   @param  RemainingDevicePath  Optional parameter use to pick a specific child
    116                                device to start.
    117 
    118   @retval EFI_SUCCESS          This driver is added to ControllerHandle
    119   @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle
    120   @retval other                This driver does not support this device
    121 
    122 **/
    123 EFI_STATUS
    124 EFIAPI
    125 DiskIoDriverBindingStart (
    126   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    127   IN EFI_HANDLE                   ControllerHandle,
    128   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
    129   )
    130 {
    131   EFI_STATUS            Status;
    132   DISK_IO_PRIVATE_DATA  *Instance;
    133   EFI_TPL               OldTpl;
    134 
    135   Instance = NULL;
    136 
    137   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    138 
    139   //
    140   // Connect to the Block IO and Block IO2 interface on ControllerHandle.
    141   //
    142   Status = gBS->OpenProtocol (
    143                   ControllerHandle,
    144                   &gEfiBlockIoProtocolGuid,
    145                   (VOID **) &gDiskIoPrivateDataTemplate.BlockIo,
    146                   This->DriverBindingHandle,
    147                   ControllerHandle,
    148                   EFI_OPEN_PROTOCOL_BY_DRIVER
    149                   );
    150   if (EFI_ERROR (Status)) {
    151     goto ErrorExit1;
    152   }
    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   }
    165 
    166   //
    167   // Initialize the Disk IO device instance.
    168   //
    169   Instance = AllocateCopyPool (sizeof (DISK_IO_PRIVATE_DATA), &gDiskIoPrivateDataTemplate);
    170   if (Instance == NULL) {
    171     Status = EFI_OUT_OF_RESOURCES;
    172     goto ErrorExit;
    173   }
    174 
    175   //
    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   //
    195   // Install protocol interfaces for the Disk IO device.
    196   //
    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   }
    211 
    212 ErrorExit:
    213   if (EFI_ERROR (Status)) {
    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);
    223     }
    224 
    225     gBS->CloseProtocol (
    226            ControllerHandle,
    227            &gEfiBlockIoProtocolGuid,
    228            This->DriverBindingHandle,
    229            ControllerHandle
    230            );
    231   }
    232 
    233 ErrorExit1:
    234   gBS->RestoreTPL (OldTpl);
    235   return Status;
    236 }
    237 
    238 /**
    239   Stop this driver on ControllerHandle by removing Disk IO protocol and closing
    240   the Block IO protocol on ControllerHandle.
    241 
    242   @param  This              Protocol instance pointer.
    243   @param  ControllerHandle  Handle of device to stop driver on
    244   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
    245                             children is zero stop the entire bus driver.
    246   @param  ChildHandleBuffer List of Child Handles to Stop.
    247 
    248   @retval EFI_SUCCESS       This driver is removed ControllerHandle
    249   @retval other             This driver was not removed from this device
    250 
    251 **/
    252 EFI_STATUS
    253 EFIAPI
    254 DiskIoDriverBindingStop (
    255   IN  EFI_DRIVER_BINDING_PROTOCOL    *This,
    256   IN  EFI_HANDLE                     ControllerHandle,
    257   IN  UINTN                          NumberOfChildren,
    258   IN  EFI_HANDLE                     *ChildHandleBuffer
    259   )
    260 {
    261   EFI_STATUS            Status;
    262   EFI_DISK_IO_PROTOCOL  *DiskIo;
    263   EFI_DISK_IO2_PROTOCOL *DiskIo2;
    264   DISK_IO_PRIVATE_DATA  *Instance;
    265   BOOLEAN               AllTaskDone;
    266 
    267   //
    268   // Get our context back.
    269   //
    270   Status = gBS->OpenProtocol (
    271                   ControllerHandle,
    272                   &gEfiDiskIoProtocolGuid,
    273                   (VOID **) &DiskIo,
    274                   This->DriverBindingHandle,
    275                   ControllerHandle,
    276                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    277                   );
    278   if (EFI_ERROR (Status)) {
    279     return Status;
    280   }
    281   Status = gBS->OpenProtocol (
    282                   ControllerHandle,
    283                   &gEfiDiskIo2ProtocolGuid,
    284                   (VOID **) &DiskIo2,
    285                   This->DriverBindingHandle,
    286                   ControllerHandle,
    287                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    288                   );
    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   }
    317   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 
    330     Status = gBS->CloseProtocol (
    331                     ControllerHandle,
    332                     &gEfiBlockIoProtocolGuid,
    333                     This->DriverBindingHandle,
    334                     ControllerHandle
    335                     );
    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);
    348   }
    349 
    350   return Status;
    351 }
    352 
    353 
    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 **/
    362 LIST_ENTRY *
    363 DiskIoDestroySubtask (
    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 **/
    402 VOID
    403 EFIAPI
    404 DiskIo2OnReadWriteComplete (
    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 **/
    461 DISK_IO_SUBTASK *
    462 DiskIoCreateSubtask (
    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 **/
    524 BOOLEAN
    525 DiskIoCreateSubtaskList (
    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 
    700 Done:
    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 **/
    720 EFI_STATUS
    721 EFIAPI
    722 DiskIo2Cancel (
    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 **/
    763 BOOLEAN
    764 DiskIo2RemoveCompletedTask (
    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 **/
    804 EFI_STATUS
    805 DiskIo2ReadWriteDisk (
    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 (Blocking) {
    837     //
    838     // Wait till pending async task is completed.
    839     //
    840     while (!DiskIo2RemoveCompletedTask (Instance));
    841 
    842     SubtasksPtr = &Subtasks;
    843   } else {
    844     DiskIo2RemoveCompletedTask (Instance);
    845     Task = AllocatePool (sizeof (DISK_IO2_TASK));
    846     if (Task == NULL) {
    847       return EFI_OUT_OF_RESOURCES;
    848     }
    849 
    850     EfiAcquireLock (&Instance->TaskQueueLock);
    851     InsertTailList (&Instance->TaskQueue, &Task->Link);
    852     EfiReleaseLock (&Instance->TaskQueueLock);
    853 
    854     Task->Signature = DISK_IO2_TASK_SIGNATURE;
    855     Task->Instance  = Instance;
    856     Task->Token     = Token;
    857     EfiInitializeLock (&Task->SubtasksLock, TPL_NOTIFY);
    858 
    859     SubtasksPtr = &Task->Subtasks;
    860   }
    861 
    862   InitializeListHead (SubtasksPtr);
    863   if (!DiskIoCreateSubtaskList (Instance, Write, Offset, BufferSize, Buffer, Blocking, Instance->SharedWorkingBuffer, SubtasksPtr)) {
    864     if (Task != NULL) {
    865       FreePool (Task);
    866     }
    867     return EFI_OUT_OF_RESOURCES;
    868   }
    869   ASSERT (!IsListEmpty (SubtasksPtr));
    870 
    871   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    872   for ( Link = GetFirstNode (SubtasksPtr), NextLink = GetNextNode (SubtasksPtr, Link)
    873       ; !IsNull (SubtasksPtr, Link)
    874       ; Link = NextLink, NextLink = GetNextNode (SubtasksPtr, NextLink)
    875       ) {
    876     Subtask         = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
    877     Subtask->Task   = Task;
    878     SubtaskBlocking = Subtask->Blocking;
    879 
    880     ASSERT ((Subtask->Length % Media->BlockSize == 0) || (Subtask->Length < Media->BlockSize));
    881 
    882     if (Subtask->Write) {
    883       //
    884       // Write
    885       //
    886       if (Subtask->WorkingBuffer != NULL) {
    887         //
    888         // A sub task before this one should be a block read operation, causing the WorkingBuffer filled with the entire one block data.
    889         //
    890         CopyMem (Subtask->WorkingBuffer + Subtask->Offset, Subtask->Buffer, Subtask->Length);
    891       }
    892 
    893       if (SubtaskBlocking) {
    894         Status = BlockIo->WriteBlocks (
    895                             BlockIo,
    896                             MediaId,
    897                             Subtask->Lba,
    898                             (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
    899                             (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
    900                             );
    901       } else {
    902         Status = BlockIo2->WriteBlocksEx (
    903                              BlockIo2,
    904                              MediaId,
    905                              Subtask->Lba,
    906                              &Subtask->BlockIo2Token,
    907                              (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
    908                              (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
    909                              );
    910       }
    911 
    912     } else {
    913       //
    914       // Read
    915       //
    916       if (SubtaskBlocking) {
    917         Status = BlockIo->ReadBlocks (
    918                             BlockIo,
    919                             MediaId,
    920                             Subtask->Lba,
    921                             (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
    922                             (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
    923                             );
    924         if (!EFI_ERROR (Status) && (Subtask->WorkingBuffer != NULL)) {
    925           CopyMem (Subtask->Buffer, Subtask->WorkingBuffer + Subtask->Offset, Subtask->Length);
    926         }
    927       } else {
    928         Status = BlockIo2->ReadBlocksEx (
    929                              BlockIo2,
    930                              MediaId,
    931                              Subtask->Lba,
    932                              &Subtask->BlockIo2Token,
    933                              (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
    934                              (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
    935                              );
    936       }
    937     }
    938 
    939     if (SubtaskBlocking || EFI_ERROR (Status)) {
    940       //
    941       // Make sure the subtask list only contains non-blocking subtasks.
    942       // Remove failed non-blocking subtasks as well because the callback won't be called.
    943       //
    944       DiskIoDestroySubtask (Instance, Subtask);
    945     }
    946 
    947     if (EFI_ERROR (Status)) {
    948       break;
    949     }
    950   }
    951 
    952   gBS->RaiseTPL (TPL_NOTIFY);
    953 
    954   //
    955   // Remove all the remaining subtasks when failure.
    956   // We shouldn't remove all the tasks because the non-blocking requests have been submitted and cannot be canceled.
    957   //
    958   if (EFI_ERROR (Status)) {
    959     while (!IsNull (SubtasksPtr, NextLink)) {
    960       Subtask = CR (NextLink, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
    961       NextLink = DiskIoDestroySubtask (Instance, Subtask);
    962     }
    963   }
    964 
    965   //
    966   // It's possible that the non-blocking subtasks finish before raising TPL to NOTIFY,
    967   // so the subtasks list might be empty at this point.
    968   //
    969   if (!Blocking && IsListEmpty (SubtasksPtr)) {
    970     EfiAcquireLock (&Instance->TaskQueueLock);
    971     RemoveEntryList (&Task->Link);
    972     EfiReleaseLock (&Instance->TaskQueueLock);
    973 
    974     if (!EFI_ERROR (Status) && (Task->Token != NULL)) {
    975       //
    976       // Task->Token should be set to NULL by the DiskIo2OnReadWriteComplete
    977       // It it's not, that means the non-blocking request was downgraded to blocking request.
    978       //
    979       DEBUG ((EFI_D_VERBOSE, "DiskIo: Non-blocking request was downgraded to blocking request, signal event directly.\n"));
    980       Task->Token->TransactionStatus = Status;
    981       gBS->SignalEvent (Task->Token->Event);
    982     }
    983 
    984     FreePool (Task);
    985   }
    986 
    987   gBS->RestoreTPL (OldTpl);
    988 
    989   return Status;
    990 }
    991 
    992 /**
    993   Reads a specified number of bytes from a device.
    994 
    995   @param This                   Indicates a pointer to the calling context.
    996   @param MediaId                ID of the medium to be read.
    997   @param Offset                 The starting byte offset on the logical block I/O device to read from.
    998   @param Token                  A pointer to the token associated with the transaction.
    999                                 If this field is NULL, synchronous/blocking IO is performed.
   1000   @param  BufferSize            The size in bytes of Buffer. The number of bytes to read from the device.
   1001   @param  Buffer                A pointer to the destination buffer for the data.
   1002                                 The caller is responsible either having implicit or explicit ownership of the buffer.
   1003 
   1004   @retval EFI_SUCCESS           If Event is NULL (blocking I/O): The data was read correctly from the device.
   1005                                 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
   1006                                                                          Event will be signaled upon completion.
   1007   @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
   1008   @retval EFI_NO_MEDIA          There is no medium in the device.
   1009   @retval EFI_MEDIA_CHNAGED     The MediaId is not for the current medium.
   1010   @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not valid for the device.
   1011   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
   1012 
   1013 **/
   1014 EFI_STATUS
   1015 EFIAPI
   1016 DiskIo2ReadDiskEx (
   1017   IN EFI_DISK_IO2_PROTOCOL        *This,
   1018   IN UINT32                       MediaId,
   1019   IN UINT64                       Offset,
   1020   IN OUT EFI_DISK_IO2_TOKEN       *Token,
   1021   IN UINTN                        BufferSize,
   1022   OUT VOID                        *Buffer
   1023   )
   1024 {
   1025   return DiskIo2ReadWriteDisk (
   1026            DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This),
   1027            FALSE, MediaId, Offset, Token, BufferSize, (UINT8 *) Buffer
   1028            );
   1029 }
   1030 
   1031 /**
   1032   Writes a specified number of bytes to a device.
   1033 
   1034   @param This        Indicates a pointer to the calling context.
   1035   @param MediaId     ID of the medium to be written.
   1036   @param Offset      The starting byte offset on the logical block I/O device to write to.
   1037   @param Token       A pointer to the token associated with the transaction.
   1038                      If this field is NULL, synchronous/blocking IO is performed.
   1039   @param BufferSize  The size in bytes of Buffer. The number of bytes to write to the device.
   1040   @param Buffer      A pointer to the buffer containing the data to be written.
   1041 
   1042   @retval EFI_SUCCESS           If Event is NULL (blocking I/O): The data was written correctly to the device.
   1043                                 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
   1044                                                                          Event will be signaled upon completion.
   1045   @retval EFI_WRITE_PROTECTED   The device cannot be written to.
   1046   @retval EFI_DEVICE_ERROR      The device reported an error while performing the write operation.
   1047   @retval EFI_NO_MEDIA          There is no medium in the device.
   1048   @retval EFI_MEDIA_CHNAGED     The MediaId is not for the current medium.
   1049   @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not valid for the device.
   1050   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
   1051 
   1052 **/
   1053 EFI_STATUS
   1054 EFIAPI
   1055 DiskIo2WriteDiskEx (
   1056   IN EFI_DISK_IO2_PROTOCOL        *This,
   1057   IN UINT32                       MediaId,
   1058   IN UINT64                       Offset,
   1059   IN OUT EFI_DISK_IO2_TOKEN       *Token,
   1060   IN UINTN                        BufferSize,
   1061   IN VOID                         *Buffer
   1062   )
   1063 {
   1064   return DiskIo2ReadWriteDisk (
   1065            DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This),
   1066            TRUE, MediaId, Offset, Token, BufferSize, (UINT8 *) Buffer
   1067            );
   1068 }
   1069 
   1070 /**
   1071   The callback for the BlockIo2 FlushBlocksEx.
   1072   @param  Event                 Event whose notification function is being invoked.
   1073   @param  Context               The pointer to the notification function's context,
   1074                                 which points to the DISK_IO2_FLUSH_TASK instance.
   1075 **/
   1076 VOID
   1077 EFIAPI
   1078 DiskIo2OnFlushComplete (
   1079   IN EFI_EVENT                 Event,
   1080   IN VOID                      *Context
   1081   )
   1082 {
   1083   DISK_IO2_FLUSH_TASK             *Task;
   1084 
   1085   gBS->CloseEvent (Event);
   1086 
   1087   Task = (DISK_IO2_FLUSH_TASK *) Context;
   1088   ASSERT (Task->Signature == DISK_IO2_FLUSH_TASK_SIGNATURE);
   1089   Task->Token->TransactionStatus = Task->BlockIo2Token.TransactionStatus;
   1090   gBS->SignalEvent (Task->Token->Event);
   1091 
   1092   FreePool (Task);
   1093 }
   1094 
   1095 /**
   1096   Flushes all modified data to the physical device.
   1097 
   1098   @param This        Indicates a pointer to the calling context.
   1099   @param Token       A pointer to the token associated with the transaction.
   1100                      If this field is NULL, synchronous/blocking IO is performed.
   1101 
   1102   @retval EFI_SUCCESS           If Event is NULL (blocking I/O): The data was flushed successfully to the device.
   1103                                 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
   1104                                                                          Event will be signaled upon completion.
   1105   @retval EFI_WRITE_PROTECTED   The device cannot be written to.
   1106   @retval EFI_DEVICE_ERROR      The device reported an error while performing the write operation.
   1107   @retval EFI_NO_MEDIA          There is no medium in the device.
   1108   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
   1109 **/
   1110 EFI_STATUS
   1111 EFIAPI
   1112 DiskIo2FlushDiskEx (
   1113   IN EFI_DISK_IO2_PROTOCOL        *This,
   1114   IN OUT EFI_DISK_IO2_TOKEN       *Token
   1115   )
   1116 {
   1117   EFI_STATUS                      Status;
   1118   DISK_IO2_FLUSH_TASK             *Task;
   1119   DISK_IO_PRIVATE_DATA            *Private;
   1120 
   1121   Private = DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This);
   1122 
   1123   if ((Token != NULL) && (Token->Event != NULL)) {
   1124     Task = AllocatePool (sizeof (DISK_IO2_FLUSH_TASK));
   1125     if (Task == NULL) {
   1126       return EFI_OUT_OF_RESOURCES;
   1127     }
   1128 
   1129     Status = gBS->CreateEvent (
   1130                     EVT_NOTIFY_SIGNAL,
   1131                     TPL_CALLBACK,
   1132                     DiskIo2OnFlushComplete,
   1133                     Task,
   1134                     &Task->BlockIo2Token.Event
   1135                     );
   1136     if (EFI_ERROR (Status)) {
   1137       FreePool (Task);
   1138       return Status;
   1139     }
   1140     Task->Signature = DISK_IO2_FLUSH_TASK_SIGNATURE;
   1141     Task->Token     = Token;
   1142     Status = Private->BlockIo2->FlushBlocksEx (Private->BlockIo2, &Task->BlockIo2Token);
   1143     if (EFI_ERROR (Status)) {
   1144       gBS->CloseEvent (Task->BlockIo2Token.Event);
   1145       FreePool (Task);
   1146     }
   1147   } else {
   1148     Status = Private->BlockIo2->FlushBlocksEx (Private->BlockIo2, NULL);
   1149   }
   1150 
   1151   return Status;
   1152 }
   1153 
   1154 /**
   1155   Read BufferSize bytes from Offset into Buffer.
   1156   Reads may support reads that are not aligned on
   1157   sector boundaries. There are three cases:
   1158     UnderRun - The first byte is not on a sector boundary or the read request is
   1159                less than a sector in length.
   1160     Aligned  - A read of N contiguous sectors.
   1161     OverRun  - The last byte is not on a sector boundary.
   1162 
   1163   @param  This                  Protocol instance pointer.
   1164   @param  MediaId               Id of the media, changes every time the media is replaced.
   1165   @param  Offset                The starting byte offset to read from
   1166   @param  BufferSize            Size of Buffer
   1167   @param  Buffer                Buffer containing read data
   1168 
   1169   @retval EFI_SUCCESS           The data was read correctly from the device.
   1170   @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.
   1171   @retval EFI_NO_MEDIA          There is no media in the device.
   1172   @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.
   1173   @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
   1174                                 valid for the device.
   1175 
   1176 **/
   1177 EFI_STATUS
   1178 EFIAPI
   1179 DiskIoReadDisk (
   1180   IN EFI_DISK_IO_PROTOCOL  *This,
   1181   IN UINT32                MediaId,
   1182   IN UINT64                Offset,
   1183   IN UINTN                 BufferSize,
   1184   OUT VOID                 *Buffer
   1185   )
   1186 {
   1187   return DiskIo2ReadWriteDisk (
   1188            DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This),
   1189            FALSE, MediaId, Offset, NULL, BufferSize, (UINT8 *) Buffer
   1190            );
   1191 }
   1192 
   1193 
   1194 /**
   1195   Writes BufferSize bytes from Buffer into Offset.
   1196   Writes may require a read modify write to support writes that are not
   1197   aligned on sector boundaries. There are three cases:
   1198     UnderRun - The first byte is not on a sector boundary or the write request
   1199                is less than a sector in length. Read modify write is required.
   1200     Aligned  - A write of N contiguous sectors.
   1201     OverRun  - The last byte is not on a sector boundary. Read modified write
   1202                required.
   1203 
   1204   @param  This       Protocol instance pointer.
   1205   @param  MediaId    Id of the media, changes every time the media is replaced.
   1206   @param  Offset     The starting byte offset to read from
   1207   @param  BufferSize Size of Buffer
   1208   @param  Buffer     Buffer containing read data
   1209 
   1210   @retval EFI_SUCCESS           The data was written correctly to the device.
   1211   @retval EFI_WRITE_PROTECTED   The device can not be written to.
   1212   @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
   1213   @retval EFI_NO_MEDIA          There is no media in the device.
   1214   @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.
   1215   @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not
   1216                                  valid for the device.
   1217 
   1218 **/
   1219 EFI_STATUS
   1220 EFIAPI
   1221 DiskIoWriteDisk (
   1222   IN EFI_DISK_IO_PROTOCOL  *This,
   1223   IN UINT32                MediaId,
   1224   IN UINT64                Offset,
   1225   IN UINTN                 BufferSize,
   1226   IN VOID                  *Buffer
   1227   )
   1228 {
   1229   return DiskIo2ReadWriteDisk (
   1230            DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This),
   1231            TRUE, MediaId, Offset, NULL, BufferSize, (UINT8 *) Buffer
   1232            );
   1233 }
   1234 
   1235 /**
   1236   The user Entry Point for module DiskIo. The user code starts with this function.
   1237 
   1238   @param[in] ImageHandle    The firmware allocated handle for the EFI image.
   1239   @param[in] SystemTable    A pointer to the EFI System Table.
   1240 
   1241   @retval EFI_SUCCESS       The entry point is executed successfully.
   1242   @retval other             Some error occurs when executing this entry point.
   1243 
   1244 **/
   1245 EFI_STATUS
   1246 EFIAPI
   1247 InitializeDiskIo (
   1248   IN EFI_HANDLE           ImageHandle,
   1249   IN EFI_SYSTEM_TABLE     *SystemTable
   1250   )
   1251 {
   1252   EFI_STATUS              Status;
   1253 
   1254   //
   1255   // Install driver model protocol(s).
   1256   //
   1257   Status = EfiLibInstallDriverBindingComponentName2 (
   1258              ImageHandle,
   1259              SystemTable,
   1260              &gDiskIoDriverBinding,
   1261              ImageHandle,
   1262              &gDiskIoComponentName,
   1263              &gDiskIoComponentName2
   1264              );
   1265   ASSERT_EFI_ERROR (Status);
   1266 
   1267   return Status;
   1268 }
   1269