Changeset 58459 in vbox for trunk/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe
- Timestamp:
- Oct 28, 2015 8:17:18 PM (9 years ago)
- Location:
- trunk/src/VBox/Devices/EFI/Firmware
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/EFI/Firmware
-
Property svn:mergeinfo
set to (toggle deleted branches)
/vendor/edk2/current 103735-103757
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c
r48674 r58459 10 10 OverRun - The last byte is not on a sector boundary. 11 11 12 Copyright (c) 2006 - 20 08, Intel Corporation. All rights reserved.<BR>12 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR> 13 13 This program and the accompanying materials 14 14 are licensed and made available under the terms and conditions of the BSD License … … 46 46 DiskIoWriteDisk 47 47 }, 48 NULL 48 { 49 EFI_DISK_IO2_PROTOCOL_REVISION, 50 DiskIo2Cancel, 51 DiskIo2ReadDiskEx, 52 DiskIo2WriteDiskEx, 53 DiskIo2FlushDiskEx 54 } 49 55 }; 50 51 56 52 57 /** … … 93 98 // 94 99 gBS->CloseProtocol ( 95 ControllerHandle,96 &gEfiBlockIoProtocolGuid,97 This->DriverBindingHandle,98 ControllerHandle99 );100 ControllerHandle, 101 &gEfiBlockIoProtocolGuid, 102 This->DriverBindingHandle, 103 ControllerHandle 104 ); 100 105 return EFI_SUCCESS; 101 106 } … … 125 130 { 126 131 EFI_STATUS Status; 127 DISK_IO_PRIVATE_DATA * Private;132 DISK_IO_PRIVATE_DATA *Instance; 128 133 EFI_TPL OldTpl; 129 134 135 Instance = NULL; 136 130 137 OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 131 Private = NULL; 132 133 // 134 // Connect to the Block IO interface on ControllerHandle. 138 139 // 140 // Connect to the Block IO and Block IO2 interface on ControllerHandle. 135 141 // 136 142 Status = gBS->OpenProtocol ( … … 145 151 goto ErrorExit1; 146 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 } 147 165 148 166 // 149 167 // Initialize the Disk IO device instance. 150 168 // 151 Private = AllocateCopyPool (sizeof (DISK_IO_PRIVATE_DATA), &gDiskIoPrivateDataTemplate);152 if ( Private == NULL) {169 Instance = AllocateCopyPool (sizeof (DISK_IO_PRIVATE_DATA), &gDiskIoPrivateDataTemplate); 170 if (Instance == NULL) { 153 171 Status = EFI_OUT_OF_RESOURCES; 154 172 goto ErrorExit; … … 156 174 157 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 // 158 195 // Install protocol interfaces for the Disk IO device. 159 196 // 160 Status = gBS->InstallProtocolInterface ( 161 &ControllerHandle, 162 &gEfiDiskIoProtocolGuid, 163 EFI_NATIVE_INTERFACE, 164 &Private->DiskIo 165 ); 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 } 166 211 167 212 ErrorExit: 168 213 if (EFI_ERROR (Status)) { 169 170 if (Private != NULL) { 171 FreePool (Private); 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); 172 223 } 173 224 174 225 gBS->CloseProtocol ( 175 ControllerHandle,176 &gEfiBlockIoProtocolGuid,177 This->DriverBindingHandle,178 ControllerHandle179 );226 ControllerHandle, 227 &gEfiBlockIoProtocolGuid, 228 This->DriverBindingHandle, 229 ControllerHandle 230 ); 180 231 } 181 232 … … 184 235 return Status; 185 236 } 186 187 237 188 238 /** … … 211 261 EFI_STATUS Status; 212 262 EFI_DISK_IO_PROTOCOL *DiskIo; 213 DISK_IO_PRIVATE_DATA *Private; 263 EFI_DISK_IO2_PROTOCOL *DiskIo2; 264 DISK_IO_PRIVATE_DATA *Instance; 265 BOOLEAN AllTaskDone; 214 266 215 267 // … … 225 277 ); 226 278 if (EFI_ERROR (Status)) { 227 return EFI_UNSUPPORTED; 228 } 229 230 Private = DISK_IO_PRIVATE_DATA_FROM_THIS (DiskIo); 231 232 Status = gBS->UninstallProtocolInterface ( 279 return Status; 280 } 281 Status = gBS->OpenProtocol ( 233 282 ControllerHandle, 234 &gEfiDiskIoProtocolGuid, 235 &Private->DiskIo 283 &gEfiDiskIo2ProtocolGuid, 284 (VOID **) &DiskIo2, 285 This->DriverBindingHandle, 286 ControllerHandle, 287 EFI_OPEN_PROTOCOL_GET_PROTOCOL 236 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 } 237 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 238 330 Status = gBS->CloseProtocol ( 239 331 ControllerHandle, … … 242 334 ControllerHandle 243 335 ); 244 } 245 246 if (!EFI_ERROR (Status)) { 247 FreePool (Private); 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); 248 348 } 249 349 … … 252 352 253 353 354 /** 355 Destroy the sub task. 356 357 @param Instance Pointer to the DISK_IO_PRIVATE_DATA. 358 @param Subtask Subtask. 359 360 @return LIST_ENTRY * Pointer to the next link of subtask. 361 **/ 362 LIST_ENTRY * 363 DiskIoDestroySubtask ( 364 IN DISK_IO_PRIVATE_DATA *Instance, 365 IN DISK_IO_SUBTASK *Subtask 366 ) 367 { 368 LIST_ENTRY *Link; 369 370 if (Subtask->Task != NULL) { 371 EfiAcquireLock (&Subtask->Task->SubtasksLock); 372 } 373 Link = RemoveEntryList (&Subtask->Link); 374 if (Subtask->Task != NULL) { 375 EfiReleaseLock (&Subtask->Task->SubtasksLock); 376 } 377 378 if (!Subtask->Blocking) { 379 if (Subtask->WorkingBuffer != NULL) { 380 FreeAlignedPages ( 381 Subtask->WorkingBuffer, 382 Subtask->Length < Instance->BlockIo->Media->BlockSize 383 ? EFI_SIZE_TO_PAGES (Instance->BlockIo->Media->BlockSize) 384 : EFI_SIZE_TO_PAGES (Subtask->Length) 385 ); 386 } 387 if (Subtask->BlockIo2Token.Event != NULL) { 388 gBS->CloseEvent (Subtask->BlockIo2Token.Event); 389 } 390 } 391 FreePool (Subtask); 392 393 return Link; 394 } 395 396 /** 397 The callback for the BlockIo2 ReadBlocksEx/WriteBlocksEx. 398 @param Event Event whose notification function is being invoked. 399 @param Context The pointer to the notification function's context, 400 which points to the DISK_IO_SUBTASK instance. 401 **/ 402 VOID 403 EFIAPI 404 DiskIo2OnReadWriteComplete ( 405 IN EFI_EVENT Event, 406 IN VOID *Context 407 ) 408 { 409 DISK_IO_SUBTASK *Subtask; 410 DISK_IO2_TASK *Task; 411 EFI_STATUS TransactionStatus; 412 DISK_IO_PRIVATE_DATA *Instance; 413 414 Subtask = (DISK_IO_SUBTASK *) Context; 415 TransactionStatus = Subtask->BlockIo2Token.TransactionStatus; 416 Task = Subtask->Task; 417 Instance = Task->Instance; 418 419 ASSERT (Subtask->Signature == DISK_IO_SUBTASK_SIGNATURE); 420 ASSERT (Instance->Signature == DISK_IO_PRIVATE_DATA_SIGNATURE); 421 ASSERT (Task->Signature == DISK_IO2_TASK_SIGNATURE); 422 423 if ((Subtask->WorkingBuffer != NULL) && !EFI_ERROR (TransactionStatus) && 424 (Task->Token != NULL) && !Subtask->Write 425 ) { 426 CopyMem (Subtask->Buffer, Subtask->WorkingBuffer + Subtask->Offset, Subtask->Length); 427 } 428 429 DiskIoDestroySubtask (Instance, Subtask); 430 431 if (EFI_ERROR (TransactionStatus) || IsListEmpty (&Task->Subtasks)) { 432 if (Task->Token != NULL) { 433 // 434 // Signal error status once the subtask is failed. 435 // Or signal the last status once the last subtask is finished. 436 // 437 Task->Token->TransactionStatus = TransactionStatus; 438 gBS->SignalEvent (Task->Token->Event); 439 440 // 441 // Mark token to NULL indicating the Task is a dead task. 442 // 443 Task->Token = NULL; 444 } 445 } 446 } 447 448 /** 449 Create the subtask. 450 451 @param Write TRUE: Write request; FALSE: Read request. 452 @param Lba The starting logical block address to read from on the device. 453 @param Offset The starting byte offset to read from the LBA. 454 @param Length The number of bytes to read from the device. 455 @param WorkingBuffer The aligned buffer to hold the data for reading or writing. 456 @param Buffer The buffer to hold the data for reading or writing. 457 @param Blocking TRUE: Blocking request; FALSE: Non-blocking request. 458 459 @return A pointer to the created subtask. 460 **/ 461 DISK_IO_SUBTASK * 462 DiskIoCreateSubtask ( 463 IN BOOLEAN Write, 464 IN UINT64 Lba, 465 IN UINT32 Offset, 466 IN UINTN Length, 467 IN VOID *WorkingBuffer, OPTIONAL 468 IN VOID *Buffer, 469 IN BOOLEAN Blocking 470 ) 471 { 472 DISK_IO_SUBTASK *Subtask; 473 EFI_STATUS Status; 474 475 Subtask = AllocateZeroPool (sizeof (DISK_IO_SUBTASK)); 476 if (Subtask == NULL) { 477 return NULL; 478 } 479 Subtask->Signature = DISK_IO_SUBTASK_SIGNATURE; 480 Subtask->Write = Write; 481 Subtask->Lba = Lba; 482 Subtask->Offset = Offset; 483 Subtask->Length = Length; 484 Subtask->WorkingBuffer = WorkingBuffer; 485 Subtask->Buffer = Buffer; 486 Subtask->Blocking = Blocking; 487 if (!Blocking) { 488 Status = gBS->CreateEvent ( 489 EVT_NOTIFY_SIGNAL, 490 TPL_NOTIFY, 491 DiskIo2OnReadWriteComplete, 492 Subtask, 493 &Subtask->BlockIo2Token.Event 494 ); 495 if (EFI_ERROR (Status)) { 496 FreePool (Subtask); 497 return NULL; 498 } 499 } 500 DEBUG (( 501 EFI_D_BLKIO, 502 " %c:Lba/Offset/Length/WorkingBuffer/Buffer = %016lx/%08x/%08x/%08x/%08x\n", 503 Write ? 'W': 'R', Lba, Offset, Length, WorkingBuffer, Buffer 504 )); 505 506 return Subtask; 507 } 508 509 /** 510 Create the subtask list. 511 512 @param Instance Pointer to the DISK_IO_PRIVATE_DATA. 513 @param Write TRUE: Write request; FALSE: Read request. 514 @param Offset The starting byte offset to read from the device. 515 @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device. 516 @param Buffer A pointer to the buffer for the data. 517 @param Blocking TRUE: Blocking request; FALSE: Non-blocking request. 518 @param SharedWorkingBuffer The aligned buffer to hold the data for reading or writing. 519 @param Subtasks The subtask list header. 520 521 @retval TRUE The subtask list is created successfully. 522 @retval FALSE The subtask list is not created. 523 **/ 524 BOOLEAN 525 DiskIoCreateSubtaskList ( 526 IN DISK_IO_PRIVATE_DATA *Instance, 527 IN BOOLEAN Write, 528 IN UINT64 Offset, 529 IN UINTN BufferSize, 530 IN VOID *Buffer, 531 IN BOOLEAN Blocking, 532 IN VOID *SharedWorkingBuffer, 533 IN OUT LIST_ENTRY *Subtasks 534 ) 535 { 536 UINT32 BlockSize; 537 UINT32 IoAlign; 538 UINT64 Lba; 539 UINT64 OverRunLba; 540 UINT32 UnderRun; 541 UINT32 OverRun; 542 UINT8 *BufferPtr; 543 UINTN Length; 544 UINTN DataBufferSize; 545 DISK_IO_SUBTASK *Subtask; 546 VOID *WorkingBuffer; 547 LIST_ENTRY *Link; 548 549 DEBUG ((EFI_D_BLKIO, "DiskIo: Create subtasks for task: Offset/BufferSize/Buffer = %016lx/%08x/%08x\n", Offset, BufferSize, Buffer)); 550 551 BlockSize = Instance->BlockIo->Media->BlockSize; 552 IoAlign = Instance->BlockIo->Media->IoAlign; 553 if (IoAlign == 0) { 554 IoAlign = 1; 555 } 556 557 Lba = DivU64x32Remainder (Offset, BlockSize, &UnderRun); 558 BufferPtr = (UINT8 *) Buffer; 559 560 // 561 // Special handling for zero BufferSize 562 // 563 if (BufferSize == 0) { 564 Subtask = DiskIoCreateSubtask (Write, Lba, UnderRun, 0, NULL, BufferPtr, Blocking); 565 if (Subtask == NULL) { 566 goto Done; 567 } 568 InsertTailList (Subtasks, &Subtask->Link); 569 return TRUE; 570 } 571 572 if (UnderRun != 0) { 573 Length = MIN (BlockSize - UnderRun, BufferSize); 574 if (Blocking) { 575 WorkingBuffer = SharedWorkingBuffer; 576 } else { 577 WorkingBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BlockSize), IoAlign); 578 if (WorkingBuffer == NULL) { 579 goto Done; 580 } 581 } 582 if (Write) { 583 // 584 // A half write operation can be splitted to a blocking block-read and half write operation 585 // This can simplify the sub task processing logic 586 // 587 Subtask = DiskIoCreateSubtask (FALSE, Lba, 0, BlockSize, NULL, WorkingBuffer, TRUE); 588 if (Subtask == NULL) { 589 goto Done; 590 } 591 InsertTailList (Subtasks, &Subtask->Link); 592 } 593 594 Subtask = DiskIoCreateSubtask (Write, Lba, UnderRun, Length, WorkingBuffer, BufferPtr, Blocking); 595 if (Subtask == NULL) { 596 goto Done; 597 } 598 InsertTailList (Subtasks, &Subtask->Link); 599 600 BufferPtr += Length; 601 Offset += Length; 602 BufferSize -= Length; 603 Lba ++; 604 } 605 606 OverRunLba = Lba + DivU64x32Remainder (BufferSize, BlockSize, &OverRun); 607 BufferSize -= OverRun; 608 609 if (OverRun != 0) { 610 if (Blocking) { 611 WorkingBuffer = SharedWorkingBuffer; 612 } else { 613 WorkingBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BlockSize), IoAlign); 614 if (WorkingBuffer == NULL) { 615 goto Done; 616 } 617 } 618 if (Write) { 619 // 620 // A half write operation can be splitted to a blocking block-read and half write operation 621 // This can simplify the sub task processing logic 622 // 623 Subtask = DiskIoCreateSubtask (FALSE, OverRunLba, 0, BlockSize, NULL, WorkingBuffer, TRUE); 624 if (Subtask == NULL) { 625 goto Done; 626 } 627 InsertTailList (Subtasks, &Subtask->Link); 628 } 629 630 Subtask = DiskIoCreateSubtask (Write, OverRunLba, 0, OverRun, WorkingBuffer, BufferPtr + BufferSize, Blocking); 631 if (Subtask == NULL) { 632 goto Done; 633 } 634 InsertTailList (Subtasks, &Subtask->Link); 635 } 636 637 if (OverRunLba > Lba) { 638 // 639 // If the DiskIo maps directly to a BlockIo device do the read. 640 // 641 if (ALIGN_POINTER (BufferPtr, IoAlign) == BufferPtr) { 642 Subtask = DiskIoCreateSubtask (Write, Lba, 0, BufferSize, NULL, BufferPtr, Blocking); 643 if (Subtask == NULL) { 644 goto Done; 645 } 646 InsertTailList (Subtasks, &Subtask->Link); 647 648 BufferPtr += BufferSize; 649 Offset += BufferSize; 650 BufferSize -= BufferSize; 651 652 } else { 653 if (Blocking) { 654 // 655 // Use the allocated buffer instead of the original buffer 656 // to avoid alignment issue. 657 // 658 for (; Lba < OverRunLba; Lba += PcdGet32 (PcdDiskIoDataBufferBlockNum)) { 659 DataBufferSize = MIN (BufferSize, PcdGet32 (PcdDiskIoDataBufferBlockNum) * BlockSize); 660 661 Subtask = DiskIoCreateSubtask (Write, Lba, 0, DataBufferSize, SharedWorkingBuffer, BufferPtr, Blocking); 662 if (Subtask == NULL) { 663 goto Done; 664 } 665 InsertTailList (Subtasks, &Subtask->Link); 666 667 BufferPtr += DataBufferSize; 668 Offset += DataBufferSize; 669 BufferSize -= DataBufferSize; 670 } 671 } else { 672 WorkingBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), IoAlign); 673 if (WorkingBuffer == NULL) { 674 // 675 // If there is not enough memory, downgrade to blocking access 676 // 677 DEBUG ((EFI_D_VERBOSE, "DiskIo: No enough memory so downgrade to blocking access\n")); 678 if (!DiskIoCreateSubtaskList (Instance, Write, Offset, BufferSize, BufferPtr, TRUE, SharedWorkingBuffer, Subtasks)) { 679 goto Done; 680 } 681 } else { 682 Subtask = DiskIoCreateSubtask (Write, Lba, 0, BufferSize, WorkingBuffer, BufferPtr, Blocking); 683 if (Subtask == NULL) { 684 goto Done; 685 } 686 InsertTailList (Subtasks, &Subtask->Link); 687 } 688 689 BufferPtr += BufferSize; 690 Offset += BufferSize; 691 BufferSize -= BufferSize; 692 } 693 } 694 } 695 696 ASSERT (BufferSize == 0); 697 698 return TRUE; 699 700 Done: 701 // 702 // Remove all the subtasks. 703 // 704 for (Link = GetFirstNode (Subtasks); !IsNull (Subtasks, Link); ) { 705 Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE); 706 Link = DiskIoDestroySubtask (Instance, Subtask); 707 } 708 return FALSE; 709 } 710 711 /** 712 Terminate outstanding asynchronous requests to a device. 713 714 @param This Indicates a pointer to the calling context. 715 716 @retval EFI_SUCCESS All outstanding requests were successfully terminated. 717 @retval EFI_DEVICE_ERROR The device reported an error while performing the cancel 718 operation. 719 **/ 720 EFI_STATUS 721 EFIAPI 722 DiskIo2Cancel ( 723 IN EFI_DISK_IO2_PROTOCOL *This 724 ) 725 { 726 DISK_IO_PRIVATE_DATA *Instance; 727 DISK_IO2_TASK *Task; 728 LIST_ENTRY *Link; 729 730 Instance = DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This); 731 732 EfiAcquireLock (&Instance->TaskQueueLock); 733 734 for (Link = GetFirstNode (&Instance->TaskQueue) 735 ; !IsNull (&Instance->TaskQueue, Link) 736 ; Link = GetNextNode (&Instance->TaskQueue, Link) 737 ) { 738 Task = CR (Link, DISK_IO2_TASK, Link, DISK_IO2_TASK_SIGNATURE); 739 740 if (Task->Token != NULL) { 741 Task->Token->TransactionStatus = EFI_ABORTED; 742 gBS->SignalEvent (Task->Token->Event); 743 // 744 // Set Token to NULL so that the further BlockIo2 responses will be ignored 745 // 746 Task->Token = NULL; 747 } 748 } 749 750 EfiReleaseLock (&Instance->TaskQueueLock); 751 752 return EFI_SUCCESS; 753 } 754 755 /** 756 Remove the completed tasks from Instance->TaskQueue. Completed tasks are those who don't have any subtasks. 757 758 @param Instance Pointer to the DISK_IO_PRIVATE_DATA. 759 760 @retval TRUE The Instance->TaskQueue is empty after the completed tasks are removed. 761 @retval FALSE The Instance->TaskQueue is not empty after the completed tasks are removed. 762 **/ 763 BOOLEAN 764 DiskIo2RemoveCompletedTask ( 765 IN DISK_IO_PRIVATE_DATA *Instance 766 ) 767 { 768 BOOLEAN QueueEmpty; 769 LIST_ENTRY *Link; 770 DISK_IO2_TASK *Task; 771 772 QueueEmpty = TRUE; 773 774 EfiAcquireLock (&Instance->TaskQueueLock); 775 for (Link = GetFirstNode (&Instance->TaskQueue); !IsNull (&Instance->TaskQueue, Link); ) { 776 Task = CR (Link, DISK_IO2_TASK, Link, DISK_IO2_TASK_SIGNATURE); 777 if (IsListEmpty (&Task->Subtasks)) { 778 Link = RemoveEntryList (&Task->Link); 779 ASSERT (Task->Token == NULL); 780 FreePool (Task); 781 } else { 782 Link = GetNextNode (&Instance->TaskQueue, Link); 783 QueueEmpty = FALSE; 784 } 785 } 786 EfiReleaseLock (&Instance->TaskQueueLock); 787 788 return QueueEmpty; 789 } 790 791 /** 792 Common routine to access the disk. 793 794 @param Instance Pointer to the DISK_IO_PRIVATE_DATA. 795 @param Write TRUE: Write operation; FALSE: Read operation. 796 @param MediaId ID of the medium to access. 797 @param Offset The starting byte offset on the logical block I/O device to access. 798 @param Token A pointer to the token associated with the transaction. 799 If this field is NULL, synchronous/blocking IO is performed. 800 @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device. 801 @param Buffer A pointer to the destination buffer for the data. 802 The caller is responsible either having implicit or explicit ownership of the buffer. 803 **/ 804 EFI_STATUS 805 DiskIo2ReadWriteDisk ( 806 IN DISK_IO_PRIVATE_DATA *Instance, 807 IN BOOLEAN Write, 808 IN UINT32 MediaId, 809 IN UINT64 Offset, 810 IN EFI_DISK_IO2_TOKEN *Token, 811 IN UINTN BufferSize, 812 IN UINT8 *Buffer 813 ) 814 { 815 EFI_STATUS Status; 816 EFI_BLOCK_IO_PROTOCOL *BlockIo; 817 EFI_BLOCK_IO2_PROTOCOL *BlockIo2; 818 EFI_BLOCK_IO_MEDIA *Media; 819 LIST_ENTRY *Link; 820 LIST_ENTRY *NextLink; 821 LIST_ENTRY Subtasks; 822 DISK_IO_SUBTASK *Subtask; 823 DISK_IO2_TASK *Task; 824 EFI_TPL OldTpl; 825 BOOLEAN Blocking; 826 BOOLEAN SubtaskBlocking; 827 LIST_ENTRY *SubtasksPtr; 828 829 Task = NULL; 830 BlockIo = Instance->BlockIo; 831 BlockIo2 = Instance->BlockIo2; 832 Media = BlockIo->Media; 833 Status = EFI_SUCCESS; 834 Blocking = (BOOLEAN) ((Token == NULL) || (Token->Event == NULL)); 835 836 if (Media->MediaId != MediaId) { 837 return EFI_MEDIA_CHANGED; 838 } 839 840 if (Write && Media->ReadOnly) { 841 return EFI_WRITE_PROTECTED; 842 } 843 844 if (Blocking) { 845 // 846 // Wait till pending async task is completed. 847 // 848 while (!DiskIo2RemoveCompletedTask (Instance)); 849 850 SubtasksPtr = &Subtasks; 851 } else { 852 DiskIo2RemoveCompletedTask (Instance); 853 Task = AllocatePool (sizeof (DISK_IO2_TASK)); 854 if (Task == NULL) { 855 return EFI_OUT_OF_RESOURCES; 856 } 857 858 EfiAcquireLock (&Instance->TaskQueueLock); 859 InsertTailList (&Instance->TaskQueue, &Task->Link); 860 EfiReleaseLock (&Instance->TaskQueueLock); 861 862 Task->Signature = DISK_IO2_TASK_SIGNATURE; 863 Task->Instance = Instance; 864 Task->Token = Token; 865 EfiInitializeLock (&Task->SubtasksLock, TPL_NOTIFY); 866 867 SubtasksPtr = &Task->Subtasks; 868 } 869 870 InitializeListHead (SubtasksPtr); 871 if (!DiskIoCreateSubtaskList (Instance, Write, Offset, BufferSize, Buffer, Blocking, Instance->SharedWorkingBuffer, SubtasksPtr)) { 872 if (Task != NULL) { 873 FreePool (Task); 874 } 875 return EFI_OUT_OF_RESOURCES; 876 } 877 ASSERT (!IsListEmpty (SubtasksPtr)); 878 879 OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 880 for ( Link = GetFirstNode (SubtasksPtr), NextLink = GetNextNode (SubtasksPtr, Link) 881 ; !IsNull (SubtasksPtr, Link) 882 ; Link = NextLink, NextLink = GetNextNode (SubtasksPtr, NextLink) 883 ) { 884 Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE); 885 Subtask->Task = Task; 886 SubtaskBlocking = Subtask->Blocking; 887 888 ASSERT ((Subtask->Length % Media->BlockSize == 0) || (Subtask->Length < Media->BlockSize)); 889 890 if (Subtask->Write) { 891 // 892 // Write 893 // 894 if (Subtask->WorkingBuffer != NULL) { 895 // 896 // A sub task before this one should be a block read operation, causing the WorkingBuffer filled with the entire one block data. 897 // 898 CopyMem (Subtask->WorkingBuffer + Subtask->Offset, Subtask->Buffer, Subtask->Length); 899 } 900 901 if (SubtaskBlocking) { 902 Status = BlockIo->WriteBlocks ( 903 BlockIo, 904 MediaId, 905 Subtask->Lba, 906 (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize, 907 (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer 908 ); 909 } else { 910 Status = BlockIo2->WriteBlocksEx ( 911 BlockIo2, 912 MediaId, 913 Subtask->Lba, 914 &Subtask->BlockIo2Token, 915 (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize, 916 (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer 917 ); 918 } 919 920 } else { 921 // 922 // Read 923 // 924 if (SubtaskBlocking) { 925 Status = BlockIo->ReadBlocks ( 926 BlockIo, 927 MediaId, 928 Subtask->Lba, 929 (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize, 930 (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer 931 ); 932 if (!EFI_ERROR (Status) && (Subtask->WorkingBuffer != NULL)) { 933 CopyMem (Subtask->Buffer, Subtask->WorkingBuffer + Subtask->Offset, Subtask->Length); 934 } 935 } else { 936 Status = BlockIo2->ReadBlocksEx ( 937 BlockIo2, 938 MediaId, 939 Subtask->Lba, 940 &Subtask->BlockIo2Token, 941 (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize, 942 (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer 943 ); 944 } 945 } 946 947 if (SubtaskBlocking || EFI_ERROR (Status)) { 948 // 949 // Make sure the subtask list only contains non-blocking subtasks. 950 // Remove failed non-blocking subtasks as well because the callback won't be called. 951 // 952 DiskIoDestroySubtask (Instance, Subtask); 953 } 954 955 if (EFI_ERROR (Status)) { 956 break; 957 } 958 } 959 960 gBS->RaiseTPL (TPL_NOTIFY); 961 962 // 963 // Remove all the remaining subtasks when failure. 964 // We shouldn't remove all the tasks because the non-blocking requests have been submitted and cannot be canceled. 965 // 966 if (EFI_ERROR (Status)) { 967 while (!IsNull (SubtasksPtr, NextLink)) { 968 Subtask = CR (NextLink, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE); 969 NextLink = DiskIoDestroySubtask (Instance, Subtask); 970 } 971 } 972 973 // 974 // It's possible that the non-blocking subtasks finish before raising TPL to NOTIFY, 975 // so the subtasks list might be empty at this point. 976 // 977 if (!Blocking && IsListEmpty (SubtasksPtr)) { 978 EfiAcquireLock (&Instance->TaskQueueLock); 979 RemoveEntryList (&Task->Link); 980 EfiReleaseLock (&Instance->TaskQueueLock); 981 982 if (!EFI_ERROR (Status) && (Task->Token != NULL)) { 983 // 984 // Task->Token should be set to NULL by the DiskIo2OnReadWriteComplete 985 // It it's not, that means the non-blocking request was downgraded to blocking request. 986 // 987 DEBUG ((EFI_D_VERBOSE, "DiskIo: Non-blocking request was downgraded to blocking request, signal event directly.\n")); 988 Task->Token->TransactionStatus = Status; 989 gBS->SignalEvent (Task->Token->Event); 990 } 991 992 FreePool (Task); 993 } 994 995 gBS->RestoreTPL (OldTpl); 996 997 return Status; 998 } 999 1000 /** 1001 Reads a specified number of bytes from a device. 1002 1003 @param This Indicates a pointer to the calling context. 1004 @param MediaId ID of the medium to be read. 1005 @param Offset The starting byte offset on the logical block I/O device to read from. 1006 @param Token A pointer to the token associated with the transaction. 1007 If this field is NULL, synchronous/blocking IO is performed. 1008 @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device. 1009 @param Buffer A pointer to the destination buffer for the data. 1010 The caller is responsible either having implicit or explicit ownership of the buffer. 1011 1012 @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was read correctly from the device. 1013 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing. 1014 Event will be signaled upon completion. 1015 @retval EFI_DEVICE_ERROR The device reported an error while performing the write. 1016 @retval EFI_NO_MEDIA There is no medium in the device. 1017 @retval EFI_MEDIA_CHNAGED The MediaId is not for the current medium. 1018 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not valid for the device. 1019 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. 1020 1021 **/ 1022 EFI_STATUS 1023 EFIAPI 1024 DiskIo2ReadDiskEx ( 1025 IN EFI_DISK_IO2_PROTOCOL *This, 1026 IN UINT32 MediaId, 1027 IN UINT64 Offset, 1028 IN OUT EFI_DISK_IO2_TOKEN *Token, 1029 IN UINTN BufferSize, 1030 OUT VOID *Buffer 1031 ) 1032 { 1033 return DiskIo2ReadWriteDisk ( 1034 DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This), 1035 FALSE, MediaId, Offset, Token, BufferSize, (UINT8 *) Buffer 1036 ); 1037 } 1038 1039 /** 1040 Writes a specified number of bytes to a device. 1041 1042 @param This Indicates a pointer to the calling context. 1043 @param MediaId ID of the medium to be written. 1044 @param Offset The starting byte offset on the logical block I/O device to write to. 1045 @param Token A pointer to the token associated with the transaction. 1046 If this field is NULL, synchronous/blocking IO is performed. 1047 @param BufferSize The size in bytes of Buffer. The number of bytes to write to the device. 1048 @param Buffer A pointer to the buffer containing the data to be written. 1049 1050 @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was written correctly to the device. 1051 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing. 1052 Event will be signaled upon completion. 1053 @retval EFI_WRITE_PROTECTED The device cannot be written to. 1054 @retval EFI_DEVICE_ERROR The device reported an error while performing the write operation. 1055 @retval EFI_NO_MEDIA There is no medium in the device. 1056 @retval EFI_MEDIA_CHNAGED The MediaId is not for the current medium. 1057 @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not valid for the device. 1058 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. 1059 1060 **/ 1061 EFI_STATUS 1062 EFIAPI 1063 DiskIo2WriteDiskEx ( 1064 IN EFI_DISK_IO2_PROTOCOL *This, 1065 IN UINT32 MediaId, 1066 IN UINT64 Offset, 1067 IN OUT EFI_DISK_IO2_TOKEN *Token, 1068 IN UINTN BufferSize, 1069 IN VOID *Buffer 1070 ) 1071 { 1072 return DiskIo2ReadWriteDisk ( 1073 DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This), 1074 TRUE, MediaId, Offset, Token, BufferSize, (UINT8 *) Buffer 1075 ); 1076 } 1077 1078 /** 1079 The callback for the BlockIo2 FlushBlocksEx. 1080 @param Event Event whose notification function is being invoked. 1081 @param Context The pointer to the notification function's context, 1082 which points to the DISK_IO2_FLUSH_TASK instance. 1083 **/ 1084 VOID 1085 EFIAPI 1086 DiskIo2OnFlushComplete ( 1087 IN EFI_EVENT Event, 1088 IN VOID *Context 1089 ) 1090 { 1091 DISK_IO2_FLUSH_TASK *Task; 1092 1093 gBS->CloseEvent (Event); 1094 1095 Task = (DISK_IO2_FLUSH_TASK *) Context; 1096 ASSERT (Task->Signature == DISK_IO2_FLUSH_TASK_SIGNATURE); 1097 Task->Token->TransactionStatus = Task->BlockIo2Token.TransactionStatus; 1098 gBS->SignalEvent (Task->Token->Event); 1099 1100 FreePool (Task); 1101 } 1102 1103 /** 1104 Flushes all modified data to the physical device. 1105 1106 @param This Indicates a pointer to the calling context. 1107 @param Token A pointer to the token associated with the transaction. 1108 If this field is NULL, synchronous/blocking IO is performed. 1109 1110 @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was flushed successfully to the device. 1111 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing. 1112 Event will be signaled upon completion. 1113 @retval EFI_WRITE_PROTECTED The device cannot be written to. 1114 @retval EFI_DEVICE_ERROR The device reported an error while performing the write operation. 1115 @retval EFI_NO_MEDIA There is no medium in the device. 1116 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. 1117 **/ 1118 EFI_STATUS 1119 EFIAPI 1120 DiskIo2FlushDiskEx ( 1121 IN EFI_DISK_IO2_PROTOCOL *This, 1122 IN OUT EFI_DISK_IO2_TOKEN *Token 1123 ) 1124 { 1125 EFI_STATUS Status; 1126 DISK_IO2_FLUSH_TASK *Task; 1127 DISK_IO_PRIVATE_DATA *Private; 1128 1129 Private = DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This); 1130 1131 if ((Token != NULL) && (Token->Event != NULL)) { 1132 Task = AllocatePool (sizeof (DISK_IO2_FLUSH_TASK)); 1133 if (Task == NULL) { 1134 return EFI_OUT_OF_RESOURCES; 1135 } 1136 1137 Status = gBS->CreateEvent ( 1138 EVT_NOTIFY_SIGNAL, 1139 TPL_CALLBACK, 1140 DiskIo2OnFlushComplete, 1141 Task, 1142 &Task->BlockIo2Token.Event 1143 ); 1144 if (EFI_ERROR (Status)) { 1145 FreePool (Task); 1146 return Status; 1147 } 1148 Task->Signature = DISK_IO2_FLUSH_TASK_SIGNATURE; 1149 Task->Token = Token; 1150 Status = Private->BlockIo2->FlushBlocksEx (Private->BlockIo2, &Task->BlockIo2Token); 1151 if (EFI_ERROR (Status)) { 1152 gBS->CloseEvent (Task->BlockIo2Token.Event); 1153 FreePool (Task); 1154 } 1155 } else { 1156 Status = Private->BlockIo2->FlushBlocksEx (Private->BlockIo2, NULL); 1157 } 1158 1159 return Status; 1160 } 254 1161 255 1162 /** … … 286 1193 ) 287 1194 { 288 EFI_STATUS Status; 289 DISK_IO_PRIVATE_DATA *Private; 290 EFI_BLOCK_IO_PROTOCOL *BlockIo; 291 EFI_BLOCK_IO_MEDIA *Media; 292 UINT32 BlockSize; 293 UINT64 Lba; 294 UINT64 OverRunLba; 295 UINT32 UnderRun; 296 UINT32 OverRun; 297 BOOLEAN TransactionComplete; 298 UINTN WorkingBufferSize; 299 UINT8 *WorkingBuffer; 300 UINTN Length; 301 UINT8 *Data; 302 UINT8 *PreData; 303 UINTN IsBufferAligned; 304 UINTN DataBufferSize; 305 BOOLEAN LastRead; 306 307 Private = DISK_IO_PRIVATE_DATA_FROM_THIS (This); 308 309 BlockIo = Private->BlockIo; 310 Media = BlockIo->Media; 311 BlockSize = Media->BlockSize; 312 313 if (Media->MediaId != MediaId) { 314 return EFI_MEDIA_CHANGED; 315 } 316 317 WorkingBuffer = Buffer; 318 WorkingBufferSize = BufferSize; 319 320 // 321 // Allocate a temporary buffer for operation 322 // 323 DataBufferSize = BlockSize * DATA_BUFFER_BLOCK_NUM; 324 325 if (Media->IoAlign > 1) { 326 PreData = AllocatePool (DataBufferSize + Media->IoAlign); 327 Data = PreData - ((UINTN) PreData & (Media->IoAlign - 1)) + Media->IoAlign; 328 } else { 329 PreData = AllocatePool (DataBufferSize); 330 Data = PreData; 331 } 332 333 if (PreData == NULL) { 334 return EFI_OUT_OF_RESOURCES; 335 } 336 337 Lba = DivU64x32Remainder (Offset, BlockSize, &UnderRun); 338 339 Length = BlockSize - UnderRun; 340 TransactionComplete = FALSE; 341 342 Status = EFI_SUCCESS; 343 if (UnderRun != 0) { 344 // 345 // Offset starts in the middle of an Lba, so read the entire block. 346 // 347 Status = BlockIo->ReadBlocks ( 348 BlockIo, 349 MediaId, 350 Lba, 351 BlockSize, 352 Data 353 ); 354 355 if (EFI_ERROR (Status)) { 356 goto Done; 357 } 358 359 if (Length > BufferSize) { 360 Length = BufferSize; 361 TransactionComplete = TRUE; 362 } 363 364 CopyMem (WorkingBuffer, Data + UnderRun, Length); 365 366 WorkingBuffer += Length; 367 368 WorkingBufferSize -= Length; 369 if (WorkingBufferSize == 0) { 370 goto Done; 371 } 372 373 Lba += 1; 374 } 375 376 OverRunLba = Lba + DivU64x32Remainder (WorkingBufferSize, BlockSize, &OverRun); 377 378 if (!TransactionComplete && WorkingBufferSize >= BlockSize) { 379 // 380 // If the DiskIo maps directly to a BlockIo device do the read. 381 // 382 if (OverRun != 0) { 383 WorkingBufferSize -= OverRun; 384 } 385 // 386 // Check buffer alignment 387 // 388 IsBufferAligned = (UINTN) WorkingBuffer & (UINTN) (Media->IoAlign - 1); 389 390 if (Media->IoAlign <= 1 || IsBufferAligned == 0) { 391 // 392 // Alignment is satisfied, so read them together 393 // 394 Status = BlockIo->ReadBlocks ( 395 BlockIo, 396 MediaId, 397 Lba, 398 WorkingBufferSize, 399 WorkingBuffer 400 ); 401 402 if (EFI_ERROR (Status)) { 403 goto Done; 404 } 405 406 WorkingBuffer += WorkingBufferSize; 407 408 } else { 409 // 410 // Use the allocated buffer instead of the original buffer 411 // to avoid alignment issue. 412 // Here, the allocated buffer (8-byte align) can satisfy the alignment 413 // 414 LastRead = FALSE; 415 do { 416 if (WorkingBufferSize <= DataBufferSize) { 417 // 418 // It is the last calling to readblocks in this loop 419 // 420 DataBufferSize = WorkingBufferSize; 421 LastRead = TRUE; 422 } 423 424 Status = BlockIo->ReadBlocks ( 425 BlockIo, 426 MediaId, 427 Lba, 428 DataBufferSize, 429 Data 430 ); 431 if (EFI_ERROR (Status)) { 432 goto Done; 433 } 434 435 CopyMem (WorkingBuffer, Data, DataBufferSize); 436 WorkingBufferSize -= DataBufferSize; 437 WorkingBuffer += DataBufferSize; 438 Lba += DATA_BUFFER_BLOCK_NUM; 439 } while (!LastRead); 440 } 441 } 442 443 if (!TransactionComplete && OverRun != 0) { 444 // 445 // Last read is not a complete block. 446 // 447 Status = BlockIo->ReadBlocks ( 448 BlockIo, 449 MediaId, 450 OverRunLba, 451 BlockSize, 452 Data 453 ); 454 455 if (EFI_ERROR (Status)) { 456 goto Done; 457 } 458 459 CopyMem (WorkingBuffer, Data, OverRun); 460 } 461 462 Done: 463 if (PreData != NULL) { 464 FreePool (PreData); 465 } 466 467 return Status; 1195 return DiskIo2ReadWriteDisk ( 1196 DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This), 1197 FALSE, MediaId, Offset, NULL, BufferSize, (UINT8 *) Buffer 1198 ); 468 1199 } 469 1200 … … 504 1235 ) 505 1236 { 506 EFI_STATUS Status; 507 DISK_IO_PRIVATE_DATA *Private; 508 EFI_BLOCK_IO_PROTOCOL *BlockIo; 509 EFI_BLOCK_IO_MEDIA *Media; 510 UINT32 BlockSize; 511 UINT64 Lba; 512 UINT64 OverRunLba; 513 UINT32 UnderRun; 514 UINT32 OverRun; 515 BOOLEAN TransactionComplete; 516 UINTN WorkingBufferSize; 517 UINT8 *WorkingBuffer; 518 UINTN Length; 519 UINT8 *Data; 520 UINT8 *PreData; 521 UINTN IsBufferAligned; 522 UINTN DataBufferSize; 523 BOOLEAN LastWrite; 524 525 Private = DISK_IO_PRIVATE_DATA_FROM_THIS (This); 526 527 BlockIo = Private->BlockIo; 528 Media = BlockIo->Media; 529 BlockSize = Media->BlockSize; 530 531 if (Media->ReadOnly) { 532 return EFI_WRITE_PROTECTED; 533 } 534 535 if (Media->MediaId != MediaId) { 536 return EFI_MEDIA_CHANGED; 537 } 538 539 DataBufferSize = BlockSize * DATA_BUFFER_BLOCK_NUM; 540 541 if (Media->IoAlign > 1) { 542 PreData = AllocatePool (DataBufferSize + Media->IoAlign); 543 Data = PreData - ((UINTN) PreData & (Media->IoAlign - 1)) + Media->IoAlign; 544 } else { 545 PreData = AllocatePool (DataBufferSize); 546 Data = PreData; 547 } 548 549 if (PreData == NULL) { 550 return EFI_OUT_OF_RESOURCES; 551 } 552 553 WorkingBuffer = Buffer; 554 WorkingBufferSize = BufferSize; 555 556 Lba = DivU64x32Remainder (Offset, BlockSize, &UnderRun); 557 558 Length = BlockSize - UnderRun; 559 TransactionComplete = FALSE; 560 561 Status = EFI_SUCCESS; 562 if (UnderRun != 0) { 563 // 564 // Offset starts in the middle of an Lba, so do read modify write. 565 // 566 Status = BlockIo->ReadBlocks ( 567 BlockIo, 568 MediaId, 569 Lba, 570 BlockSize, 571 Data 572 ); 573 574 if (EFI_ERROR (Status)) { 575 goto Done; 576 } 577 578 if (Length > BufferSize) { 579 Length = BufferSize; 580 TransactionComplete = TRUE; 581 } 582 583 CopyMem (Data + UnderRun, WorkingBuffer, Length); 584 585 Status = BlockIo->WriteBlocks ( 586 BlockIo, 587 MediaId, 588 Lba, 589 BlockSize, 590 Data 591 ); 592 if (EFI_ERROR (Status)) { 593 goto Done; 594 } 595 596 WorkingBuffer += Length; 597 WorkingBufferSize -= Length; 598 if (WorkingBufferSize == 0) { 599 goto Done; 600 } 601 602 Lba += 1; 603 } 604 605 OverRunLba = Lba + DivU64x32Remainder (WorkingBufferSize, BlockSize, &OverRun); 606 607 if (!TransactionComplete && WorkingBufferSize >= BlockSize) { 608 // 609 // If the DiskIo maps directly to a BlockIo device do the write. 610 // 611 if (OverRun != 0) { 612 WorkingBufferSize -= OverRun; 613 } 614 // 615 // Check buffer alignment 616 // 617 IsBufferAligned = (UINTN) WorkingBuffer & (UINTN) (Media->IoAlign - 1); 618 619 if (Media->IoAlign <= 1 || IsBufferAligned == 0) { 620 // 621 // Alignment is satisfied, so write them together 622 // 623 Status = BlockIo->WriteBlocks ( 624 BlockIo, 625 MediaId, 626 Lba, 627 WorkingBufferSize, 628 WorkingBuffer 629 ); 630 631 if (EFI_ERROR (Status)) { 632 goto Done; 633 } 634 635 WorkingBuffer += WorkingBufferSize; 636 637 } else { 638 // 639 // The buffer parameter is not aligned with the request 640 // So use the allocated instead. 641 // It can fit almost all the cases. 642 // 643 LastWrite = FALSE; 644 do { 645 if (WorkingBufferSize <= DataBufferSize) { 646 // 647 // It is the last calling to writeblocks in this loop 648 // 649 DataBufferSize = WorkingBufferSize; 650 LastWrite = TRUE; 651 } 652 653 CopyMem (Data, WorkingBuffer, DataBufferSize); 654 Status = BlockIo->WriteBlocks ( 655 BlockIo, 656 MediaId, 657 Lba, 658 DataBufferSize, 659 Data 660 ); 661 if (EFI_ERROR (Status)) { 662 goto Done; 663 } 664 665 WorkingBufferSize -= DataBufferSize; 666 WorkingBuffer += DataBufferSize; 667 Lba += DATA_BUFFER_BLOCK_NUM; 668 } while (!LastWrite); 669 } 670 } 671 672 if (!TransactionComplete && OverRun != 0) { 673 // 674 // Last bit is not a complete block, so do a read modify write. 675 // 676 Status = BlockIo->ReadBlocks ( 677 BlockIo, 678 MediaId, 679 OverRunLba, 680 BlockSize, 681 Data 682 ); 683 684 if (EFI_ERROR (Status)) { 685 goto Done; 686 } 687 688 CopyMem (Data, WorkingBuffer, OverRun); 689 690 Status = BlockIo->WriteBlocks ( 691 BlockIo, 692 MediaId, 693 OverRunLba, 694 BlockSize, 695 Data 696 ); 697 if (EFI_ERROR (Status)) { 698 goto Done; 699 } 700 } 701 702 Done: 703 if (PreData != NULL) { 704 FreePool (PreData); 705 } 706 707 return Status; 708 } 709 1237 return DiskIo2ReadWriteDisk ( 1238 DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This), 1239 TRUE, MediaId, Offset, NULL, BufferSize, (UINT8 *) Buffer 1240 ); 1241 } 710 1242 711 1243 /** … … 741 1273 ASSERT_EFI_ERROR (Status); 742 1274 743 744 1275 return Status; 745 1276 } 746 -
trunk/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.h
r48674 r58459 2 2 Master header file for DiskIo driver. It includes the module private defininitions. 3 3 4 Copyright (c) 2006 - 201 1, Intel Corporation. All rights reserved.<BR>4 Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR> 5 5 This program and the accompanying materials 6 6 are licensed and made available under the terms and conditions of the BSD License … … 18 18 #include <Uefi.h> 19 19 #include <Protocol/BlockIo.h> 20 #include <Protocol/BlockIo2.h> 21 #include <Protocol/DiskIo2.h> 20 22 #include <Protocol/ComponentName.h> 21 23 #include <Protocol/DriverBinding.h> … … 29 31 #include <Library/UefiBootServicesTableLib.h> 30 32 31 32 #define DATA_BUFFER_BLOCK_NUM 6433 34 33 #define DISK_IO_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('d', 's', 'k', 'I') 35 36 34 typedef struct { 37 UINTN Signature; 38 EFI_DISK_IO_PROTOCOL DiskIo; 39 EFI_BLOCK_IO_PROTOCOL *BlockIo; 35 UINT32 Signature; 36 37 EFI_DISK_IO_PROTOCOL DiskIo; 38 EFI_DISK_IO2_PROTOCOL DiskIo2; 39 EFI_BLOCK_IO_PROTOCOL *BlockIo; 40 EFI_BLOCK_IO2_PROTOCOL *BlockIo2; 41 42 UINT8 *SharedWorkingBuffer; 43 44 EFI_LOCK TaskQueueLock; 45 LIST_ENTRY TaskQueue; 40 46 } DISK_IO_PRIVATE_DATA; 41 42 #define DISK_IO_PRIVATE_DATA_FROM_THIS(a) CR (a, DISK_IO_PRIVATE_DATA, DiskIo, DISK_IO_PRIVATE_DATA_SIGNATURE) 47 #define DISK_IO_PRIVATE_DATA_FROM_DISK_IO(a) CR (a, DISK_IO_PRIVATE_DATA, DiskIo, DISK_IO_PRIVATE_DATA_SIGNATURE) 48 #define DISK_IO_PRIVATE_DATA_FROM_DISK_IO2(a) CR (a, DISK_IO_PRIVATE_DATA, DiskIo2, DISK_IO_PRIVATE_DATA_SIGNATURE) 49 50 #define DISK_IO2_TASK_SIGNATURE SIGNATURE_32 ('d', 'i', 'a', 't') 51 typedef struct { 52 UINT32 Signature; 53 LIST_ENTRY Link; /// < link to other task 54 EFI_LOCK SubtasksLock; 55 LIST_ENTRY Subtasks; /// < header of subtasks 56 EFI_DISK_IO2_TOKEN *Token; 57 DISK_IO_PRIVATE_DATA *Instance; 58 } DISK_IO2_TASK; 59 60 #define DISK_IO2_FLUSH_TASK_SIGNATURE SIGNATURE_32 ('d', 'i', 'f', 't') 61 typedef struct { 62 UINT32 Signature; 63 EFI_BLOCK_IO2_TOKEN BlockIo2Token; 64 EFI_DISK_IO2_TOKEN *Token; 65 } DISK_IO2_FLUSH_TASK; 66 67 #define DISK_IO_SUBTASK_SIGNATURE SIGNATURE_32 ('d', 'i', 's', 't') 68 typedef struct { 69 // 70 // UnderRun: Offset != 0, Length < BlockSize 71 // OverRun: Offset == 0, Length < BlockSize 72 // Middle: Offset is block aligned, Length is multiple of block size 73 // 74 UINT32 Signature; 75 LIST_ENTRY Link; 76 BOOLEAN Write; 77 UINT64 Lba; 78 UINT32 Offset; 79 UINTN Length; 80 UINT8 *WorkingBuffer; /// < NULL indicates using "Buffer" directly 81 UINT8 *Buffer; 82 BOOLEAN Blocking; 83 84 // 85 // Following fields are for DiskIo2 86 // 87 DISK_IO2_TASK *Task; 88 EFI_BLOCK_IO2_TOKEN BlockIo2Token; 89 } DISK_IO_SUBTASK; 43 90 44 91 // … … 190 237 ); 191 238 239 240 /** 241 Terminate outstanding asynchronous requests to a device. 242 243 @param This Indicates a pointer to the calling context. 244 245 @retval EFI_SUCCESS All outstanding requests were successfully terminated. 246 @retval EFI_DEVICE_ERROR The device reported an error while performing the cancel 247 operation. 248 **/ 249 EFI_STATUS 250 EFIAPI 251 DiskIo2Cancel ( 252 IN EFI_DISK_IO2_PROTOCOL *This 253 ); 254 255 /** 256 Reads a specified number of bytes from a device. 257 258 @param This Indicates a pointer to the calling context. 259 @param MediaId ID of the medium to be read. 260 @param Offset The starting byte offset on the logical block I/O device to read from. 261 @param Token A pointer to the token associated with the transaction. 262 If this field is NULL, synchronous/blocking IO is performed. 263 @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device. 264 @param Buffer A pointer to the destination buffer for the data. 265 The caller is responsible either having implicit or explicit ownership of the buffer. 266 267 @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was read correctly from the device. 268 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing. 269 Event will be signaled upon completion. 270 @retval EFI_DEVICE_ERROR The device reported an error while performing the write. 271 @retval EFI_NO_MEDIA There is no medium in the device. 272 @retval EFI_MEDIA_CHNAGED The MediaId is not for the current medium. 273 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not valid for the device. 274 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. 275 276 **/ 277 EFI_STATUS 278 EFIAPI 279 DiskIo2ReadDiskEx ( 280 IN EFI_DISK_IO2_PROTOCOL *This, 281 IN UINT32 MediaId, 282 IN UINT64 Offset, 283 IN OUT EFI_DISK_IO2_TOKEN *Token, 284 IN UINTN BufferSize, 285 OUT VOID *Buffer 286 ); 287 288 /** 289 Writes a specified number of bytes to a device. 290 291 @param This Indicates a pointer to the calling context. 292 @param MediaId ID of the medium to be written. 293 @param Offset The starting byte offset on the logical block I/O device to write to. 294 @param Token A pointer to the token associated with the transaction. 295 If this field is NULL, synchronous/blocking IO is performed. 296 @param BufferSize The size in bytes of Buffer. The number of bytes to write to the device. 297 @param Buffer A pointer to the buffer containing the data to be written. 298 299 @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was written correctly to the device. 300 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing. 301 Event will be signaled upon completion. 302 @retval EFI_WRITE_PROTECTED The device cannot be written to. 303 @retval EFI_DEVICE_ERROR The device reported an error while performing the write operation. 304 @retval EFI_NO_MEDIA There is no medium in the device. 305 @retval EFI_MEDIA_CHNAGED The MediaId is not for the current medium. 306 @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not valid for the device. 307 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. 308 309 **/ 310 EFI_STATUS 311 EFIAPI 312 DiskIo2WriteDiskEx ( 313 IN EFI_DISK_IO2_PROTOCOL *This, 314 IN UINT32 MediaId, 315 IN UINT64 Offset, 316 IN EFI_DISK_IO2_TOKEN *Token, 317 IN UINTN BufferSize, 318 IN VOID *Buffer 319 ); 320 321 /** 322 Flushes all modified data to the physical device. 323 324 @param This Indicates a pointer to the calling context. 325 @param Token A pointer to the token associated with the transaction. 326 If this field is NULL, synchronous/blocking IO is performed. 327 328 @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was flushed successfully to the device. 329 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing. 330 Event will be signaled upon completion. 331 @retval EFI_WRITE_PROTECTED The device cannot be written to. 332 @retval EFI_DEVICE_ERROR The device reported an error while performing the write operation. 333 @retval EFI_NO_MEDIA There is no medium in the device. 334 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. 335 **/ 336 EFI_STATUS 337 EFIAPI 338 DiskIo2FlushDiskEx ( 339 IN EFI_DISK_IO2_PROTOCOL *This, 340 IN OUT EFI_DISK_IO2_TOKEN *Token 341 ); 342 192 343 // 193 344 // EFI Component Name Functions -
trunk/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf
r48674 r58459 9 9 # code utilize the Disk I/O protocol. 10 10 # 11 # Copyright (c) 2006 - 201 0, Intel Corporation. All rights reserved.<BR>11 # Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR> 12 12 # This program and the accompanying materials 13 13 # are licensed and made available under the terms and conditions of the BSD License … … 23 23 INF_VERSION = 0x00010005 24 24 BASE_NAME = DiskIoDxe 25 MODULE_UNI_FILE = DiskIoDxe.uni 25 26 FILE_GUID = 6B38F7B4-AD98-40e9-9093-ACA2B5A253C4 26 27 MODULE_TYPE = UEFI_DRIVER … … 46 47 [Packages] 47 48 MdePkg/MdePkg.dec 48 49 MdeModulePkg/MdeModulePkg.dec 49 50 50 51 [LibraryClasses] … … 56 57 UefiDriverEntryPoint 57 58 DebugLib 58 59 PcdLib 59 60 60 61 [Protocols] 61 62 gEfiDiskIoProtocolGuid ## BY_START 63 gEfiDiskIo2ProtocolGuid ## BY_START 62 64 gEfiBlockIoProtocolGuid ## TO_START 65 gEfiBlockIo2ProtocolGuid ## TO_START 63 66 67 [Pcd] 68 gEfiMdeModulePkgTokenSpaceGuid.PcdDiskIoDataBufferBlockNum ## SOMETIMES_CONSUMES 69 70 [UserExtensions.TianoCore."ExtraFiles"] 71 DiskIoDxeExtra.uni
Note:
See TracChangeset
for help on using the changeset viewer.