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