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 - 2018, Intel Corporation. All rights reserved.<BR>
13 SPDX-License-Identifier: BSD-2-Clause-Patent
14 
15 **/
16 
17 #include "DiskIo.h"
18 
19 //
20 // Driver binding protocol implementation for DiskIo driver.
21 //
22 EFI_DRIVER_BINDING_PROTOCOL gDiskIoDriverBinding = {
23   DiskIoDriverBindingSupported,
24   DiskIoDriverBindingStart,
25   DiskIoDriverBindingStop,
26   0xa,
27   NULL,
28   NULL
29 };
30 
31 //
32 // Template for DiskIo private data structure.
33 // The pointer to BlockIo protocol interface is assigned dynamically.
34 //
35 DISK_IO_PRIVATE_DATA        gDiskIoPrivateDataTemplate = {
36   DISK_IO_PRIVATE_DATA_SIGNATURE,
37   {
38     EFI_DISK_IO_PROTOCOL_REVISION,
39     DiskIoReadDisk,
40     DiskIoWriteDisk
41   },
42   {
43     EFI_DISK_IO2_PROTOCOL_REVISION,
44     DiskIo2Cancel,
45     DiskIo2ReadDiskEx,
46     DiskIo2WriteDiskEx,
47     DiskIo2FlushDiskEx
48   }
49 };
50 
51 /**
52   Test to see if this driver supports ControllerHandle.
53 
54   @param  This                Protocol instance pointer.
55   @param  ControllerHandle    Handle of device to test
56   @param  RemainingDevicePath Optional parameter use to pick a specific child
57                               device to start.
58 
59   @retval EFI_SUCCESS         This driver supports this device
60   @retval EFI_ALREADY_STARTED This driver is already running on this device
61   @retval other               This driver does not support this device
62 
63 **/
64 EFI_STATUS
65 EFIAPI
DiskIoDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)66 DiskIoDriverBindingSupported (
67   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
68   IN EFI_HANDLE                   ControllerHandle,
69   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
70   )
71 {
72   EFI_STATUS            Status;
73   EFI_BLOCK_IO_PROTOCOL *BlockIo;
74 
75   //
76   // Open the IO Abstraction(s) needed to perform the supported test.
77   //
78   Status = gBS->OpenProtocol (
79                   ControllerHandle,
80                   &gEfiBlockIoProtocolGuid,
81                   (VOID **) &BlockIo,
82                   This->DriverBindingHandle,
83                   ControllerHandle,
84                   EFI_OPEN_PROTOCOL_BY_DRIVER
85                   );
86   if (EFI_ERROR (Status)) {
87     return Status;
88   }
89 
90   //
91   // Close the I/O Abstraction(s) used to perform the supported test.
92   //
93   gBS->CloseProtocol (
94          ControllerHandle,
95          &gEfiBlockIoProtocolGuid,
96          This->DriverBindingHandle,
97          ControllerHandle
98          );
99   return EFI_SUCCESS;
100 }
101 
102 
103 /**
104   Start this driver on ControllerHandle by opening a Block IO protocol and
105   installing a Disk IO protocol on ControllerHandle.
106 
107   @param  This                 Protocol instance pointer.
108   @param  ControllerHandle     Handle of device to bind driver to
109   @param  RemainingDevicePath  Optional parameter use to pick a specific child
110                                device to start.
111 
112   @retval EFI_SUCCESS          This driver is added to ControllerHandle
113   @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle
114   @retval other                This driver does not support this device
115 
116 **/
117 EFI_STATUS
118 EFIAPI
DiskIoDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)119 DiskIoDriverBindingStart (
120   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
121   IN EFI_HANDLE                   ControllerHandle,
122   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
123   )
124 {
125   EFI_STATUS            Status;
126   DISK_IO_PRIVATE_DATA  *Instance;
127   EFI_TPL               OldTpl;
128 
129   Instance = NULL;
130 
131   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
132 
133   //
134   // Connect to the Block IO and Block IO2 interface on ControllerHandle.
135   //
136   Status = gBS->OpenProtocol (
137                   ControllerHandle,
138                   &gEfiBlockIoProtocolGuid,
139                   (VOID **) &gDiskIoPrivateDataTemplate.BlockIo,
140                   This->DriverBindingHandle,
141                   ControllerHandle,
142                   EFI_OPEN_PROTOCOL_BY_DRIVER
143                   );
144   if (EFI_ERROR (Status)) {
145     goto ErrorExit1;
146   }
147 
148   Status = gBS->OpenProtocol (
149                   ControllerHandle,
150                   &gEfiBlockIo2ProtocolGuid,
151                   (VOID **) &gDiskIoPrivateDataTemplate.BlockIo2,
152                   This->DriverBindingHandle,
153                   ControllerHandle,
154                   EFI_OPEN_PROTOCOL_BY_DRIVER
155                   );
156   if (EFI_ERROR (Status)) {
157     gDiskIoPrivateDataTemplate.BlockIo2 = NULL;
158   }
159 
160   //
161   // Initialize the Disk IO device instance.
162   //
163   Instance = AllocateCopyPool (sizeof (DISK_IO_PRIVATE_DATA), &gDiskIoPrivateDataTemplate);
164   if (Instance == NULL) {
165     Status = EFI_OUT_OF_RESOURCES;
166     goto ErrorExit;
167   }
168 
169   //
170   // The BlockSize and IoAlign of BlockIo and BlockIo2 should equal.
171   //
172   ASSERT ((Instance->BlockIo2 == NULL) ||
173           ((Instance->BlockIo->Media->IoAlign == Instance->BlockIo2->Media->IoAlign) &&
174            (Instance->BlockIo->Media->BlockSize == Instance->BlockIo2->Media->BlockSize)
175           ));
176 
177   InitializeListHead (&Instance->TaskQueue);
178   EfiInitializeLock (&Instance->TaskQueueLock, TPL_NOTIFY);
179   Instance->SharedWorkingBuffer = AllocateAlignedPages (
180                                     EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum) * Instance->BlockIo->Media->BlockSize),
181                                     Instance->BlockIo->Media->IoAlign
182                                     );
183   if (Instance->SharedWorkingBuffer == NULL) {
184     Status = EFI_OUT_OF_RESOURCES;
185     goto ErrorExit;
186   }
187 
188   //
189   // Install protocol interfaces for the Disk IO device.
190   //
191   if (Instance->BlockIo2 != NULL) {
192     Status = gBS->InstallMultipleProtocolInterfaces (
193                     &ControllerHandle,
194                     &gEfiDiskIoProtocolGuid,  &Instance->DiskIo,
195                     &gEfiDiskIo2ProtocolGuid, &Instance->DiskIo2,
196                     NULL
197                     );
198   } else {
199     Status = gBS->InstallMultipleProtocolInterfaces (
200                     &ControllerHandle,
201                     &gEfiDiskIoProtocolGuid,  &Instance->DiskIo,
202                     NULL
203                     );
204   }
205 
206 ErrorExit:
207   if (EFI_ERROR (Status)) {
208     if (Instance != NULL && Instance->SharedWorkingBuffer != NULL) {
209       FreeAlignedPages (
210         Instance->SharedWorkingBuffer,
211         EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum) * Instance->BlockIo->Media->BlockSize)
212         );
213     }
214 
215     if (Instance != NULL) {
216       FreePool (Instance);
217     }
218 
219     gBS->CloseProtocol (
220            ControllerHandle,
221            &gEfiBlockIoProtocolGuid,
222            This->DriverBindingHandle,
223            ControllerHandle
224            );
225   }
226 
227 ErrorExit1:
228   gBS->RestoreTPL (OldTpl);
229   return Status;
230 }
231 
232 /**
233   Stop this driver on ControllerHandle by removing Disk IO protocol and closing
234   the Block IO protocol on ControllerHandle.
235 
236   @param  This              Protocol instance pointer.
237   @param  ControllerHandle  Handle of device to stop driver on
238   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
239                             children is zero stop the entire bus driver.
240   @param  ChildHandleBuffer List of Child Handles to Stop.
241 
242   @retval EFI_SUCCESS       This driver is removed ControllerHandle
243   @retval other             This driver was not removed from this device
244 
245 **/
246 EFI_STATUS
247 EFIAPI
DiskIoDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)248 DiskIoDriverBindingStop (
249   IN  EFI_DRIVER_BINDING_PROTOCOL    *This,
250   IN  EFI_HANDLE                     ControllerHandle,
251   IN  UINTN                          NumberOfChildren,
252   IN  EFI_HANDLE                     *ChildHandleBuffer
253   )
254 {
255   EFI_STATUS            Status;
256   EFI_DISK_IO_PROTOCOL  *DiskIo;
257   EFI_DISK_IO2_PROTOCOL *DiskIo2;
258   DISK_IO_PRIVATE_DATA  *Instance;
259   BOOLEAN               AllTaskDone;
260 
261   //
262   // Get our context back.
263   //
264   Status = gBS->OpenProtocol (
265                   ControllerHandle,
266                   &gEfiDiskIoProtocolGuid,
267                   (VOID **) &DiskIo,
268                   This->DriverBindingHandle,
269                   ControllerHandle,
270                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
271                   );
272   if (EFI_ERROR (Status)) {
273     return Status;
274   }
275   Status = gBS->OpenProtocol (
276                   ControllerHandle,
277                   &gEfiDiskIo2ProtocolGuid,
278                   (VOID **) &DiskIo2,
279                   This->DriverBindingHandle,
280                   ControllerHandle,
281                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
282                   );
283   if (EFI_ERROR (Status)) {
284     DiskIo2 = NULL;
285   }
286 
287   Instance = DISK_IO_PRIVATE_DATA_FROM_DISK_IO (DiskIo);
288 
289   if (DiskIo2 != NULL) {
290     //
291     // Call BlockIo2::Reset() to terminate any in-flight non-blocking I/O requests
292     //
293     ASSERT (Instance->BlockIo2 != NULL);
294     Status = Instance->BlockIo2->Reset (Instance->BlockIo2, FALSE);
295     if (EFI_ERROR (Status)) {
296       return Status;
297     }
298     Status = gBS->UninstallMultipleProtocolInterfaces (
299                     ControllerHandle,
300                     &gEfiDiskIoProtocolGuid,  &Instance->DiskIo,
301                     &gEfiDiskIo2ProtocolGuid, &Instance->DiskIo2,
302                     NULL
303                     );
304   } else {
305     Status = gBS->UninstallMultipleProtocolInterfaces (
306                     ControllerHandle,
307                     &gEfiDiskIoProtocolGuid,  &Instance->DiskIo,
308                     NULL
309                     );
310   }
311   if (!EFI_ERROR (Status)) {
312 
313     do {
314       EfiAcquireLock (&Instance->TaskQueueLock);
315       AllTaskDone = IsListEmpty (&Instance->TaskQueue);
316       EfiReleaseLock (&Instance->TaskQueueLock);
317     } while (!AllTaskDone);
318 
319     FreeAlignedPages (
320       Instance->SharedWorkingBuffer,
321       EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum) * Instance->BlockIo->Media->BlockSize)
322       );
323 
324     Status = gBS->CloseProtocol (
325                     ControllerHandle,
326                     &gEfiBlockIoProtocolGuid,
327                     This->DriverBindingHandle,
328                     ControllerHandle
329                     );
330     ASSERT_EFI_ERROR (Status);
331     if (DiskIo2 != NULL) {
332       Status = gBS->CloseProtocol (
333                       ControllerHandle,
334                       &gEfiBlockIo2ProtocolGuid,
335                       This->DriverBindingHandle,
336                       ControllerHandle
337                       );
338       ASSERT_EFI_ERROR (Status);
339     }
340 
341     FreePool (Instance);
342   }
343 
344   return Status;
345 }
346 
347 
348 /**
349   Destroy the sub task.
350 
351   @param Instance     Pointer to the DISK_IO_PRIVATE_DATA.
352   @param Subtask      Subtask.
353 
354   @return LIST_ENTRY *  Pointer to the next link of subtask.
355 **/
356 LIST_ENTRY *
DiskIoDestroySubtask(IN DISK_IO_PRIVATE_DATA * Instance,IN DISK_IO_SUBTASK * Subtask)357 DiskIoDestroySubtask (
358   IN DISK_IO_PRIVATE_DATA     *Instance,
359   IN DISK_IO_SUBTASK          *Subtask
360   )
361 {
362   LIST_ENTRY               *Link;
363 
364   if (Subtask->Task != NULL) {
365     EfiAcquireLock (&Subtask->Task->SubtasksLock);
366   }
367   Link = RemoveEntryList (&Subtask->Link);
368   if (Subtask->Task != NULL) {
369     EfiReleaseLock (&Subtask->Task->SubtasksLock);
370   }
371 
372   if (!Subtask->Blocking) {
373     if (Subtask->WorkingBuffer != NULL) {
374       FreeAlignedPages (
375         Subtask->WorkingBuffer,
376         Subtask->Length < Instance->BlockIo->Media->BlockSize
377         ? EFI_SIZE_TO_PAGES (Instance->BlockIo->Media->BlockSize)
378         : EFI_SIZE_TO_PAGES (Subtask->Length)
379         );
380     }
381     if (Subtask->BlockIo2Token.Event != NULL) {
382       gBS->CloseEvent (Subtask->BlockIo2Token.Event);
383     }
384   }
385   FreePool (Subtask);
386 
387   return Link;
388 }
389 
390 /**
391   The callback for the BlockIo2 ReadBlocksEx/WriteBlocksEx.
392   @param  Event                 Event whose notification function is being invoked.
393   @param  Context               The pointer to the notification function's context,
394                                 which points to the DISK_IO_SUBTASK instance.
395 **/
396 VOID
397 EFIAPI
DiskIo2OnReadWriteComplete(IN EFI_EVENT Event,IN VOID * Context)398 DiskIo2OnReadWriteComplete (
399   IN EFI_EVENT            Event,
400   IN VOID                 *Context
401   )
402 {
403   DISK_IO_SUBTASK       *Subtask;
404   DISK_IO2_TASK         *Task;
405   EFI_STATUS            TransactionStatus;
406   DISK_IO_PRIVATE_DATA  *Instance;
407 
408   Subtask           = (DISK_IO_SUBTASK *) Context;
409   TransactionStatus = Subtask->BlockIo2Token.TransactionStatus;
410   Task              = Subtask->Task;
411   Instance          = Task->Instance;
412 
413   ASSERT (Subtask->Signature  == DISK_IO_SUBTASK_SIGNATURE);
414   ASSERT (Instance->Signature == DISK_IO_PRIVATE_DATA_SIGNATURE);
415   ASSERT (Task->Signature     == DISK_IO2_TASK_SIGNATURE);
416 
417   if ((Subtask->WorkingBuffer != NULL) && !EFI_ERROR (TransactionStatus) &&
418       (Task->Token != NULL) && !Subtask->Write
419      ) {
420     CopyMem (Subtask->Buffer, Subtask->WorkingBuffer + Subtask->Offset, Subtask->Length);
421   }
422 
423   DiskIoDestroySubtask (Instance, Subtask);
424 
425   if (EFI_ERROR (TransactionStatus) || IsListEmpty (&Task->Subtasks)) {
426     if (Task->Token != NULL) {
427       //
428       // Signal error status once the subtask is failed.
429       // Or signal the last status once the last subtask is finished.
430       //
431       Task->Token->TransactionStatus = TransactionStatus;
432       gBS->SignalEvent (Task->Token->Event);
433 
434       //
435       // Mark token to NULL indicating the Task is a dead task.
436       //
437       Task->Token = NULL;
438     }
439   }
440 }
441 
442 /**
443   Create the subtask.
444 
445   @param Write         TRUE: Write request; FALSE: Read request.
446   @param Lba           The starting logical block address to read from on the device.
447   @param Offset        The starting byte offset to read from the LBA.
448   @param Length        The number of bytes to read from the device.
449   @param WorkingBuffer The aligned buffer to hold the data for reading or writing.
450   @param Buffer        The buffer to hold the data for reading or writing.
451   @param Blocking      TRUE: Blocking request; FALSE: Non-blocking request.
452 
453   @return A pointer to the created subtask.
454 **/
455 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)456 DiskIoCreateSubtask (
457   IN BOOLEAN          Write,
458   IN UINT64           Lba,
459   IN UINT32           Offset,
460   IN UINTN            Length,
461   IN VOID             *WorkingBuffer,  OPTIONAL
462   IN VOID             *Buffer,
463   IN BOOLEAN          Blocking
464   )
465 {
466   DISK_IO_SUBTASK       *Subtask;
467   EFI_STATUS            Status;
468 
469   Subtask = AllocateZeroPool (sizeof (DISK_IO_SUBTASK));
470   if (Subtask == NULL) {
471     return NULL;
472   }
473   Subtask->Signature     = DISK_IO_SUBTASK_SIGNATURE;
474   Subtask->Write         = Write;
475   Subtask->Lba           = Lba;
476   Subtask->Offset        = Offset;
477   Subtask->Length        = Length;
478   Subtask->WorkingBuffer = WorkingBuffer;
479   Subtask->Buffer        = Buffer;
480   Subtask->Blocking      = Blocking;
481   if (!Blocking) {
482     Status = gBS->CreateEvent (
483                     EVT_NOTIFY_SIGNAL,
484                     TPL_NOTIFY,
485                     DiskIo2OnReadWriteComplete,
486                     Subtask,
487                     &Subtask->BlockIo2Token.Event
488                     );
489     if (EFI_ERROR (Status)) {
490       FreePool (Subtask);
491       return NULL;
492     }
493   }
494   DEBUG ((
495     EFI_D_BLKIO,
496     "  %c:Lba/Offset/Length/WorkingBuffer/Buffer = %016lx/%08x/%08x/%08x/%08x\n",
497     Write ? 'W': 'R', Lba, Offset, Length, WorkingBuffer, Buffer
498     ));
499 
500   return Subtask;
501 }
502 
503 /**
504   Create the subtask list.
505 
506   @param Instance            Pointer to the DISK_IO_PRIVATE_DATA.
507   @param Write               TRUE: Write request; FALSE: Read request.
508   @param Offset              The starting byte offset to read from the device.
509   @param BufferSize          The size in bytes of Buffer. The number of bytes to read from the device.
510   @param Buffer              A pointer to the buffer for the data.
511   @param Blocking            TRUE: Blocking request; FALSE: Non-blocking request.
512   @param SharedWorkingBuffer The aligned buffer to hold the data for reading or writing.
513   @param Subtasks            The subtask list header.
514 
515   @retval TRUE  The subtask list is created successfully.
516   @retval FALSE The subtask list is not created.
517 **/
518 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)519 DiskIoCreateSubtaskList (
520   IN DISK_IO_PRIVATE_DATA  *Instance,
521   IN BOOLEAN               Write,
522   IN UINT64                Offset,
523   IN UINTN                 BufferSize,
524   IN VOID                  *Buffer,
525   IN BOOLEAN               Blocking,
526   IN VOID                  *SharedWorkingBuffer,
527   IN OUT LIST_ENTRY        *Subtasks
528   )
529 {
530   UINT32                BlockSize;
531   UINT32                IoAlign;
532   UINT64                Lba;
533   UINT64                OverRunLba;
534   UINT32                UnderRun;
535   UINT32                OverRun;
536   UINT8                 *BufferPtr;
537   UINTN                 Length;
538   UINTN                 DataBufferSize;
539   DISK_IO_SUBTASK       *Subtask;
540   VOID                  *WorkingBuffer;
541   LIST_ENTRY            *Link;
542 
543   DEBUG ((EFI_D_BLKIO, "DiskIo: Create subtasks for task: Offset/BufferSize/Buffer = %016lx/%08x/%08x\n", Offset, BufferSize, Buffer));
544 
545   BlockSize = Instance->BlockIo->Media->BlockSize;
546   IoAlign   = Instance->BlockIo->Media->IoAlign;
547   if (IoAlign == 0) {
548     IoAlign = 1;
549   }
550 
551   Lba       = DivU64x32Remainder (Offset, BlockSize, &UnderRun);
552   BufferPtr = (UINT8 *) Buffer;
553 
554   //
555   // Special handling for zero BufferSize
556   //
557   if (BufferSize == 0) {
558     Subtask = DiskIoCreateSubtask (Write, Lba, UnderRun, 0, NULL, BufferPtr, Blocking);
559     if (Subtask == NULL) {
560       goto Done;
561     }
562     InsertTailList (Subtasks, &Subtask->Link);
563     return TRUE;
564   }
565 
566   if (UnderRun != 0) {
567     Length = MIN (BlockSize - UnderRun, BufferSize);
568     if (Blocking) {
569       WorkingBuffer = SharedWorkingBuffer;
570     } else {
571       WorkingBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BlockSize), IoAlign);
572       if (WorkingBuffer == NULL) {
573         goto Done;
574       }
575     }
576     if (Write) {
577       //
578       // A half write operation can be splitted to a blocking block-read and half write operation
579       // This can simplify the sub task processing logic
580       //
581       Subtask = DiskIoCreateSubtask (FALSE, Lba, 0, BlockSize, NULL, WorkingBuffer, TRUE);
582       if (Subtask == NULL) {
583         goto Done;
584       }
585       InsertTailList (Subtasks, &Subtask->Link);
586     }
587 
588     Subtask = DiskIoCreateSubtask (Write, Lba, UnderRun, Length, WorkingBuffer, BufferPtr, Blocking);
589     if (Subtask == NULL) {
590       goto Done;
591     }
592     InsertTailList (Subtasks, &Subtask->Link);
593 
594     BufferPtr  += Length;
595     Offset     += Length;
596     BufferSize -= Length;
597     Lba ++;
598   }
599 
600   OverRunLba  = Lba + DivU64x32Remainder (BufferSize, BlockSize, &OverRun);
601   BufferSize -= OverRun;
602 
603   if (OverRun != 0) {
604     if (Blocking) {
605       WorkingBuffer = SharedWorkingBuffer;
606     } else {
607       WorkingBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BlockSize), IoAlign);
608       if (WorkingBuffer == NULL) {
609         goto Done;
610       }
611     }
612     if (Write) {
613       //
614       // A half write operation can be splitted to a blocking block-read and half write operation
615       // This can simplify the sub task processing logic
616       //
617       Subtask = DiskIoCreateSubtask (FALSE, OverRunLba, 0, BlockSize, NULL, WorkingBuffer, TRUE);
618       if (Subtask == NULL) {
619         goto Done;
620       }
621       InsertTailList (Subtasks, &Subtask->Link);
622     }
623 
624     Subtask = DiskIoCreateSubtask (Write, OverRunLba, 0, OverRun, WorkingBuffer, BufferPtr + BufferSize, Blocking);
625     if (Subtask == NULL) {
626       goto Done;
627     }
628     InsertTailList (Subtasks, &Subtask->Link);
629   }
630 
631   if (OverRunLba > Lba) {
632     //
633     // If the DiskIo maps directly to a BlockIo device do the read.
634     //
635     if (ALIGN_POINTER (BufferPtr, IoAlign) == BufferPtr) {
636       Subtask = DiskIoCreateSubtask (Write, Lba, 0, BufferSize, NULL, BufferPtr, Blocking);
637       if (Subtask == NULL) {
638         goto Done;
639       }
640       InsertTailList (Subtasks, &Subtask->Link);
641 
642       BufferPtr  += BufferSize;
643       Offset     += BufferSize;
644       BufferSize -= BufferSize;
645 
646     } else {
647       if (Blocking) {
648         //
649         // Use the allocated buffer instead of the original buffer
650         // to avoid alignment issue.
651         //
652         for (; Lba < OverRunLba; Lba += PcdGet32 (PcdDiskIoDataBufferBlockNum)) {
653           DataBufferSize = MIN (BufferSize, PcdGet32 (PcdDiskIoDataBufferBlockNum) * BlockSize);
654 
655           Subtask = DiskIoCreateSubtask (Write, Lba, 0, DataBufferSize, SharedWorkingBuffer, BufferPtr, Blocking);
656           if (Subtask == NULL) {
657             goto Done;
658           }
659           InsertTailList (Subtasks, &Subtask->Link);
660 
661           BufferPtr  += DataBufferSize;
662           Offset     += DataBufferSize;
663           BufferSize -= DataBufferSize;
664         }
665       } else {
666         WorkingBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), IoAlign);
667         if (WorkingBuffer == NULL) {
668           //
669           // If there is not enough memory, downgrade to blocking access
670           //
671           DEBUG ((EFI_D_VERBOSE, "DiskIo: No enough memory so downgrade to blocking access\n"));
672           if (!DiskIoCreateSubtaskList (Instance, Write, Offset, BufferSize, BufferPtr, TRUE, SharedWorkingBuffer, Subtasks)) {
673             goto Done;
674           }
675         } else {
676           Subtask = DiskIoCreateSubtask (Write, Lba, 0, BufferSize, WorkingBuffer, BufferPtr, Blocking);
677           if (Subtask == NULL) {
678             goto Done;
679           }
680           InsertTailList (Subtasks, &Subtask->Link);
681         }
682 
683         BufferPtr  += BufferSize;
684         Offset     += BufferSize;
685         BufferSize -= BufferSize;
686       }
687     }
688   }
689 
690   ASSERT (BufferSize == 0);
691 
692   return TRUE;
693 
694 Done:
695   //
696   // Remove all the subtasks.
697   //
698   for (Link = GetFirstNode (Subtasks); !IsNull (Subtasks, Link); ) {
699     Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
700     Link = DiskIoDestroySubtask (Instance, Subtask);
701   }
702   return FALSE;
703 }
704 
705 /**
706   Terminate outstanding asynchronous requests to a device.
707 
708   @param This                   Indicates a pointer to the calling context.
709 
710   @retval EFI_SUCCESS           All outstanding requests were successfully terminated.
711   @retval EFI_DEVICE_ERROR      The device reported an error while performing the cancel
712                                 operation.
713 **/
714 EFI_STATUS
715 EFIAPI
DiskIo2Cancel(IN EFI_DISK_IO2_PROTOCOL * This)716 DiskIo2Cancel (
717   IN EFI_DISK_IO2_PROTOCOL *This
718   )
719 {
720   DISK_IO_PRIVATE_DATA  *Instance;
721   DISK_IO2_TASK         *Task;
722   LIST_ENTRY            *Link;
723 
724   Instance = DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This);
725 
726   EfiAcquireLock (&Instance->TaskQueueLock);
727 
728   for (Link = GetFirstNode (&Instance->TaskQueue)
729     ; !IsNull (&Instance->TaskQueue, Link)
730     ; Link = GetNextNode (&Instance->TaskQueue, Link)
731     ) {
732     Task = CR (Link, DISK_IO2_TASK, Link, DISK_IO2_TASK_SIGNATURE);
733 
734     if (Task->Token != NULL) {
735       Task->Token->TransactionStatus = EFI_ABORTED;
736       gBS->SignalEvent (Task->Token->Event);
737       //
738       // Set Token to NULL so that the further BlockIo2 responses will be ignored
739       //
740       Task->Token = NULL;
741     }
742   }
743 
744   EfiReleaseLock (&Instance->TaskQueueLock);
745 
746   return EFI_SUCCESS;
747 }
748 
749 /**
750   Remove the completed tasks from Instance->TaskQueue. Completed tasks are those who don't have any subtasks.
751 
752   @param Instance    Pointer to the DISK_IO_PRIVATE_DATA.
753 
754   @retval TRUE       The Instance->TaskQueue is empty after the completed tasks are removed.
755   @retval FALSE      The Instance->TaskQueue is not empty after the completed tasks are removed.
756 **/
757 BOOLEAN
DiskIo2RemoveCompletedTask(IN DISK_IO_PRIVATE_DATA * Instance)758 DiskIo2RemoveCompletedTask (
759   IN DISK_IO_PRIVATE_DATA     *Instance
760   )
761 {
762   BOOLEAN                     QueueEmpty;
763   LIST_ENTRY                  *Link;
764   DISK_IO2_TASK               *Task;
765 
766   QueueEmpty = TRUE;
767 
768   EfiAcquireLock (&Instance->TaskQueueLock);
769   for (Link = GetFirstNode (&Instance->TaskQueue); !IsNull (&Instance->TaskQueue, Link); ) {
770     Task = CR (Link, DISK_IO2_TASK, Link, DISK_IO2_TASK_SIGNATURE);
771     if (IsListEmpty (&Task->Subtasks)) {
772       Link = RemoveEntryList (&Task->Link);
773       ASSERT (Task->Token == NULL);
774       FreePool (Task);
775     } else {
776       Link = GetNextNode (&Instance->TaskQueue, Link);
777       QueueEmpty = FALSE;
778     }
779   }
780   EfiReleaseLock (&Instance->TaskQueueLock);
781 
782   return QueueEmpty;
783 }
784 
785 /**
786   Common routine to access the disk.
787 
788   @param Instance    Pointer to the DISK_IO_PRIVATE_DATA.
789   @param Write       TRUE: Write operation; FALSE: Read operation.
790   @param MediaId     ID of the medium to access.
791   @param Offset      The starting byte offset on the logical block I/O device to access.
792   @param Token       A pointer to the token associated with the transaction.
793                      If this field is NULL, synchronous/blocking IO is performed.
794   @param  BufferSize            The size in bytes of Buffer. The number of bytes to read from the device.
795   @param  Buffer                A pointer to the destination buffer for the data.
796                                 The caller is responsible either having implicit or explicit ownership of the buffer.
797 **/
798 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)799 DiskIo2ReadWriteDisk (
800   IN DISK_IO_PRIVATE_DATA     *Instance,
801   IN BOOLEAN                  Write,
802   IN UINT32                   MediaId,
803   IN UINT64                   Offset,
804   IN EFI_DISK_IO2_TOKEN       *Token,
805   IN UINTN                    BufferSize,
806   IN UINT8                    *Buffer
807   )
808 {
809   EFI_STATUS             Status;
810   EFI_BLOCK_IO_PROTOCOL  *BlockIo;
811   EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
812   EFI_BLOCK_IO_MEDIA     *Media;
813   LIST_ENTRY             *Link;
814   LIST_ENTRY             *NextLink;
815   LIST_ENTRY             Subtasks;
816   DISK_IO_SUBTASK        *Subtask;
817   DISK_IO2_TASK          *Task;
818   EFI_TPL                OldTpl;
819   BOOLEAN                Blocking;
820   BOOLEAN                SubtaskBlocking;
821   LIST_ENTRY             *SubtasksPtr;
822 
823   Task      = NULL;
824   BlockIo   = Instance->BlockIo;
825   BlockIo2  = Instance->BlockIo2;
826   Media     = BlockIo->Media;
827   Status    = EFI_SUCCESS;
828   Blocking  = (BOOLEAN) ((Token == NULL) || (Token->Event == NULL));
829 
830   if (Blocking) {
831     //
832     // Wait till pending async task is completed.
833     //
834     while (!DiskIo2RemoveCompletedTask (Instance));
835 
836     SubtasksPtr = &Subtasks;
837   } else {
838     DiskIo2RemoveCompletedTask (Instance);
839     Task = AllocatePool (sizeof (DISK_IO2_TASK));
840     if (Task == NULL) {
841       return EFI_OUT_OF_RESOURCES;
842     }
843 
844     EfiAcquireLock (&Instance->TaskQueueLock);
845     InsertTailList (&Instance->TaskQueue, &Task->Link);
846     EfiReleaseLock (&Instance->TaskQueueLock);
847 
848     Task->Signature = DISK_IO2_TASK_SIGNATURE;
849     Task->Instance  = Instance;
850     Task->Token     = Token;
851     EfiInitializeLock (&Task->SubtasksLock, TPL_NOTIFY);
852 
853     SubtasksPtr = &Task->Subtasks;
854   }
855 
856   InitializeListHead (SubtasksPtr);
857   if (!DiskIoCreateSubtaskList (Instance, Write, Offset, BufferSize, Buffer, Blocking, Instance->SharedWorkingBuffer, SubtasksPtr)) {
858     if (Task != NULL) {
859       FreePool (Task);
860     }
861     return EFI_OUT_OF_RESOURCES;
862   }
863   ASSERT (!IsListEmpty (SubtasksPtr));
864 
865   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
866   for ( Link = GetFirstNode (SubtasksPtr), NextLink = GetNextNode (SubtasksPtr, Link)
867       ; !IsNull (SubtasksPtr, Link)
868       ; Link = NextLink, NextLink = GetNextNode (SubtasksPtr, NextLink)
869       ) {
870     Subtask         = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
871     Subtask->Task   = Task;
872     SubtaskBlocking = Subtask->Blocking;
873 
874     ASSERT ((Subtask->Length % Media->BlockSize == 0) || (Subtask->Length < Media->BlockSize));
875 
876     if (Subtask->Write) {
877       //
878       // Write
879       //
880       if (Subtask->WorkingBuffer != NULL) {
881         //
882         // A sub task before this one should be a block read operation, causing the WorkingBuffer filled with the entire one block data.
883         //
884         CopyMem (Subtask->WorkingBuffer + Subtask->Offset, Subtask->Buffer, Subtask->Length);
885       }
886 
887       if (SubtaskBlocking) {
888         Status = BlockIo->WriteBlocks (
889                             BlockIo,
890                             MediaId,
891                             Subtask->Lba,
892                             (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
893                             (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
894                             );
895       } else {
896         Status = BlockIo2->WriteBlocksEx (
897                              BlockIo2,
898                              MediaId,
899                              Subtask->Lba,
900                              &Subtask->BlockIo2Token,
901                              (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
902                              (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
903                              );
904       }
905 
906     } else {
907       //
908       // Read
909       //
910       if (SubtaskBlocking) {
911         Status = BlockIo->ReadBlocks (
912                             BlockIo,
913                             MediaId,
914                             Subtask->Lba,
915                             (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
916                             (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
917                             );
918         if (!EFI_ERROR (Status) && (Subtask->WorkingBuffer != NULL)) {
919           CopyMem (Subtask->Buffer, Subtask->WorkingBuffer + Subtask->Offset, Subtask->Length);
920         }
921       } else {
922         Status = BlockIo2->ReadBlocksEx (
923                              BlockIo2,
924                              MediaId,
925                              Subtask->Lba,
926                              &Subtask->BlockIo2Token,
927                              (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
928                              (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
929                              );
930       }
931     }
932 
933     if (SubtaskBlocking || EFI_ERROR (Status)) {
934       //
935       // Make sure the subtask list only contains non-blocking subtasks.
936       // Remove failed non-blocking subtasks as well because the callback won't be called.
937       //
938       DiskIoDestroySubtask (Instance, Subtask);
939     }
940 
941     if (EFI_ERROR (Status)) {
942       break;
943     }
944   }
945 
946   gBS->RaiseTPL (TPL_NOTIFY);
947 
948   //
949   // Remove all the remaining subtasks when failure.
950   // We shouldn't remove all the tasks because the non-blocking requests have been submitted and cannot be canceled.
951   //
952   if (EFI_ERROR (Status)) {
953     while (!IsNull (SubtasksPtr, NextLink)) {
954       Subtask = CR (NextLink, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
955       NextLink = DiskIoDestroySubtask (Instance, Subtask);
956     }
957   }
958 
959   //
960   // It's possible that the non-blocking subtasks finish before raising TPL to NOTIFY,
961   // so the subtasks list might be empty at this point.
962   //
963   if (!Blocking && IsListEmpty (SubtasksPtr)) {
964     EfiAcquireLock (&Instance->TaskQueueLock);
965     RemoveEntryList (&Task->Link);
966     EfiReleaseLock (&Instance->TaskQueueLock);
967 
968     if (!EFI_ERROR (Status) && (Task->Token != NULL)) {
969       //
970       // Task->Token should be set to NULL by the DiskIo2OnReadWriteComplete
971       // It it's not, that means the non-blocking request was downgraded to blocking request.
972       //
973       DEBUG ((EFI_D_VERBOSE, "DiskIo: Non-blocking request was downgraded to blocking request, signal event directly.\n"));
974       Task->Token->TransactionStatus = Status;
975       gBS->SignalEvent (Task->Token->Event);
976     }
977 
978     FreePool (Task);
979   }
980 
981   gBS->RestoreTPL (OldTpl);
982 
983   return Status;
984 }
985 
986 /**
987   Reads a specified number of bytes from a device.
988 
989   @param This                   Indicates a pointer to the calling context.
990   @param MediaId                ID of the medium to be read.
991   @param Offset                 The starting byte offset on the logical block I/O device to read from.
992   @param Token                  A pointer to the token associated with the transaction.
993                                 If this field is NULL, synchronous/blocking IO is performed.
994   @param  BufferSize            The size in bytes of Buffer. The number of bytes to read from the device.
995   @param  Buffer                A pointer to the destination buffer for the data.
996                                 The caller is responsible either having implicit or explicit ownership of the buffer.
997 
998   @retval EFI_SUCCESS           If Event is NULL (blocking I/O): The data was read correctly from the device.
999                                 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
1000                                                                          Event will be signaled upon completion.
1001   @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
1002   @retval EFI_NO_MEDIA          There is no medium in the device.
1003   @retval EFI_MEDIA_CHNAGED     The MediaId is not for the current medium.
1004   @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not valid for the device.
1005   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
1006 
1007 **/
1008 EFI_STATUS
1009 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)1010 DiskIo2ReadDiskEx (
1011   IN EFI_DISK_IO2_PROTOCOL        *This,
1012   IN UINT32                       MediaId,
1013   IN UINT64                       Offset,
1014   IN OUT EFI_DISK_IO2_TOKEN       *Token,
1015   IN UINTN                        BufferSize,
1016   OUT VOID                        *Buffer
1017   )
1018 {
1019   return DiskIo2ReadWriteDisk (
1020            DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This),
1021            FALSE, MediaId, Offset, Token, BufferSize, (UINT8 *) Buffer
1022            );
1023 }
1024 
1025 /**
1026   Writes a specified number of bytes to a device.
1027 
1028   @param This        Indicates a pointer to the calling context.
1029   @param MediaId     ID of the medium to be written.
1030   @param Offset      The starting byte offset on the logical block I/O device to write to.
1031   @param Token       A pointer to the token associated with the transaction.
1032                      If this field is NULL, synchronous/blocking IO is performed.
1033   @param BufferSize  The size in bytes of Buffer. The number of bytes to write to the device.
1034   @param Buffer      A pointer to the buffer containing the data to be written.
1035 
1036   @retval EFI_SUCCESS           If Event is NULL (blocking I/O): The data was written correctly to the device.
1037                                 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
1038                                                                          Event will be signaled upon completion.
1039   @retval EFI_WRITE_PROTECTED   The device cannot be written to.
1040   @retval EFI_DEVICE_ERROR      The device reported an error while performing the write operation.
1041   @retval EFI_NO_MEDIA          There is no medium in the device.
1042   @retval EFI_MEDIA_CHNAGED     The MediaId is not for the current medium.
1043   @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not valid for the device.
1044   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
1045 
1046 **/
1047 EFI_STATUS
1048 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)1049 DiskIo2WriteDiskEx (
1050   IN EFI_DISK_IO2_PROTOCOL        *This,
1051   IN UINT32                       MediaId,
1052   IN UINT64                       Offset,
1053   IN OUT EFI_DISK_IO2_TOKEN       *Token,
1054   IN UINTN                        BufferSize,
1055   IN VOID                         *Buffer
1056   )
1057 {
1058   return DiskIo2ReadWriteDisk (
1059            DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This),
1060            TRUE, MediaId, Offset, Token, BufferSize, (UINT8 *) Buffer
1061            );
1062 }
1063 
1064 /**
1065   The callback for the BlockIo2 FlushBlocksEx.
1066   @param  Event                 Event whose notification function is being invoked.
1067   @param  Context               The pointer to the notification function's context,
1068                                 which points to the DISK_IO2_FLUSH_TASK instance.
1069 **/
1070 VOID
1071 EFIAPI
DiskIo2OnFlushComplete(IN EFI_EVENT Event,IN VOID * Context)1072 DiskIo2OnFlushComplete (
1073   IN EFI_EVENT                 Event,
1074   IN VOID                      *Context
1075   )
1076 {
1077   DISK_IO2_FLUSH_TASK             *Task;
1078 
1079   gBS->CloseEvent (Event);
1080 
1081   Task = (DISK_IO2_FLUSH_TASK *) Context;
1082   ASSERT (Task->Signature == DISK_IO2_FLUSH_TASK_SIGNATURE);
1083   Task->Token->TransactionStatus = Task->BlockIo2Token.TransactionStatus;
1084   gBS->SignalEvent (Task->Token->Event);
1085 
1086   FreePool (Task);
1087 }
1088 
1089 /**
1090   Flushes all modified data to the physical device.
1091 
1092   @param This        Indicates a pointer to the calling context.
1093   @param Token       A pointer to the token associated with the transaction.
1094                      If this field is NULL, synchronous/blocking IO is performed.
1095 
1096   @retval EFI_SUCCESS           If Event is NULL (blocking I/O): The data was flushed successfully to the device.
1097                                 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
1098                                                                          Event will be signaled upon completion.
1099   @retval EFI_WRITE_PROTECTED   The device cannot be written to.
1100   @retval EFI_DEVICE_ERROR      The device reported an error while performing the write operation.
1101   @retval EFI_NO_MEDIA          There is no medium in the device.
1102   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
1103 **/
1104 EFI_STATUS
1105 EFIAPI
DiskIo2FlushDiskEx(IN EFI_DISK_IO2_PROTOCOL * This,IN OUT EFI_DISK_IO2_TOKEN * Token)1106 DiskIo2FlushDiskEx (
1107   IN EFI_DISK_IO2_PROTOCOL        *This,
1108   IN OUT EFI_DISK_IO2_TOKEN       *Token
1109   )
1110 {
1111   EFI_STATUS                      Status;
1112   DISK_IO2_FLUSH_TASK             *Task;
1113   DISK_IO_PRIVATE_DATA            *Private;
1114 
1115   Private = DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This);
1116 
1117   if ((Token != NULL) && (Token->Event != NULL)) {
1118     Task = AllocatePool (sizeof (DISK_IO2_FLUSH_TASK));
1119     if (Task == NULL) {
1120       return EFI_OUT_OF_RESOURCES;
1121     }
1122 
1123     Status = gBS->CreateEvent (
1124                     EVT_NOTIFY_SIGNAL,
1125                     TPL_CALLBACK,
1126                     DiskIo2OnFlushComplete,
1127                     Task,
1128                     &Task->BlockIo2Token.Event
1129                     );
1130     if (EFI_ERROR (Status)) {
1131       FreePool (Task);
1132       return Status;
1133     }
1134     Task->Signature = DISK_IO2_FLUSH_TASK_SIGNATURE;
1135     Task->Token     = Token;
1136     Status = Private->BlockIo2->FlushBlocksEx (Private->BlockIo2, &Task->BlockIo2Token);
1137     if (EFI_ERROR (Status)) {
1138       gBS->CloseEvent (Task->BlockIo2Token.Event);
1139       FreePool (Task);
1140     }
1141   } else {
1142     Status = Private->BlockIo2->FlushBlocksEx (Private->BlockIo2, NULL);
1143   }
1144 
1145   return Status;
1146 }
1147 
1148 /**
1149   Read BufferSize bytes from Offset into Buffer.
1150   Reads may support reads that are not aligned on
1151   sector boundaries. There are three cases:
1152     UnderRun - The first byte is not on a sector boundary or the read request is
1153                less than a sector in length.
1154     Aligned  - A read of N contiguous sectors.
1155     OverRun  - The last byte is not on a sector boundary.
1156 
1157   @param  This                  Protocol instance pointer.
1158   @param  MediaId               Id of the media, changes every time the media is replaced.
1159   @param  Offset                The starting byte offset to read from
1160   @param  BufferSize            Size of Buffer
1161   @param  Buffer                Buffer containing read data
1162 
1163   @retval EFI_SUCCESS           The data was read correctly from the device.
1164   @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.
1165   @retval EFI_NO_MEDIA          There is no media in the device.
1166   @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.
1167   @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
1168                                 valid for the device.
1169 
1170 **/
1171 EFI_STATUS
1172 EFIAPI
DiskIoReadDisk(IN EFI_DISK_IO_PROTOCOL * This,IN UINT32 MediaId,IN UINT64 Offset,IN UINTN BufferSize,OUT VOID * Buffer)1173 DiskIoReadDisk (
1174   IN EFI_DISK_IO_PROTOCOL  *This,
1175   IN UINT32                MediaId,
1176   IN UINT64                Offset,
1177   IN UINTN                 BufferSize,
1178   OUT VOID                 *Buffer
1179   )
1180 {
1181   return DiskIo2ReadWriteDisk (
1182            DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This),
1183            FALSE, MediaId, Offset, NULL, BufferSize, (UINT8 *) Buffer
1184            );
1185 }
1186 
1187 
1188 /**
1189   Writes BufferSize bytes from Buffer into Offset.
1190   Writes may require a read modify write to support writes that are not
1191   aligned on sector boundaries. There are three cases:
1192     UnderRun - The first byte is not on a sector boundary or the write request
1193                is less than a sector in length. Read modify write is required.
1194     Aligned  - A write of N contiguous sectors.
1195     OverRun  - The last byte is not on a sector boundary. Read modified write
1196                required.
1197 
1198   @param  This       Protocol instance pointer.
1199   @param  MediaId    Id of the media, changes every time the media is replaced.
1200   @param  Offset     The starting byte offset to read from
1201   @param  BufferSize Size of Buffer
1202   @param  Buffer     Buffer containing read data
1203 
1204   @retval EFI_SUCCESS           The data was written correctly to the device.
1205   @retval EFI_WRITE_PROTECTED   The device can not be written to.
1206   @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
1207   @retval EFI_NO_MEDIA          There is no media in the device.
1208   @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.
1209   @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not
1210                                  valid for the device.
1211 
1212 **/
1213 EFI_STATUS
1214 EFIAPI
DiskIoWriteDisk(IN EFI_DISK_IO_PROTOCOL * This,IN UINT32 MediaId,IN UINT64 Offset,IN UINTN BufferSize,IN VOID * Buffer)1215 DiskIoWriteDisk (
1216   IN EFI_DISK_IO_PROTOCOL  *This,
1217   IN UINT32                MediaId,
1218   IN UINT64                Offset,
1219   IN UINTN                 BufferSize,
1220   IN VOID                  *Buffer
1221   )
1222 {
1223   return DiskIo2ReadWriteDisk (
1224            DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This),
1225            TRUE, MediaId, Offset, NULL, BufferSize, (UINT8 *) Buffer
1226            );
1227 }
1228 
1229 /**
1230   The user Entry Point for module DiskIo. The user code starts with this function.
1231 
1232   @param[in] ImageHandle    The firmware allocated handle for the EFI image.
1233   @param[in] SystemTable    A pointer to the EFI System Table.
1234 
1235   @retval EFI_SUCCESS       The entry point is executed successfully.
1236   @retval other             Some error occurs when executing this entry point.
1237 
1238 **/
1239 EFI_STATUS
1240 EFIAPI
InitializeDiskIo(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1241 InitializeDiskIo (
1242   IN EFI_HANDLE           ImageHandle,
1243   IN EFI_SYSTEM_TABLE     *SystemTable
1244   )
1245 {
1246   EFI_STATUS              Status;
1247 
1248   //
1249   // Install driver model protocol(s).
1250   //
1251   Status = EfiLibInstallDriverBindingComponentName2 (
1252              ImageHandle,
1253              SystemTable,
1254              &gDiskIoDriverBinding,
1255              ImageHandle,
1256              &gDiskIoComponentName,
1257              &gDiskIoComponentName2
1258              );
1259   ASSERT_EFI_ERROR (Status);
1260 
1261   return Status;
1262 }
1263