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
DiskIoDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)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
DiskIoDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)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
DiskIoDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)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 *
DiskIoDestroySubtask(IN DISK_IO_PRIVATE_DATA * Instance,IN DISK_IO_SUBTASK * Subtask)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
DiskIo2OnReadWriteComplete(IN EFI_EVENT Event,IN VOID * Context)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 *
DiskIoCreateSubtask(IN BOOLEAN Write,IN UINT64 Lba,IN UINT32 Offset,IN UINTN Length,IN VOID * WorkingBuffer,OPTIONAL IN VOID * Buffer,IN BOOLEAN Blocking)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
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)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
DiskIo2Cancel(IN EFI_DISK_IO2_PROTOCOL * This)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
DiskIo2RemoveCompletedTask(IN DISK_IO_PRIVATE_DATA * Instance)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
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)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
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)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
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)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
DiskIo2OnFlushComplete(IN EFI_EVENT Event,IN VOID * Context)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
DiskIo2FlushDiskEx(IN EFI_DISK_IO2_PROTOCOL * This,IN OUT EFI_DISK_IO2_TOKEN * Token)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
DiskIoReadDisk(IN EFI_DISK_IO_PROTOCOL * This,IN UINT32 MediaId,IN UINT64 Offset,IN UINTN BufferSize,OUT VOID * Buffer)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
DiskIoWriteDisk(IN EFI_DISK_IO_PROTOCOL * This,IN UINT32 MediaId,IN UINT64 Offset,IN UINTN BufferSize,IN VOID * Buffer)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
InitializeDiskIo(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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