1 /** @file 2 Partition driver that produces logical BlockIo devices from a physical 3 BlockIo device. The logical BlockIo devices are based on the format 4 of the raw block devices media. Currently "El Torito CD-ROM", Legacy 5 MBR, and GPT partition schemes are supported. 6 7 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR> 8 This program and the accompanying materials 9 are licensed and made available under the terms and conditions of the BSD License 10 which accompanies this distribution. The full text of the license may be found at 11 http://opensource.org/licenses/bsd-license.php 12 13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 15 16 **/ 17 18 19 #include "Partition.h" 20 21 // 22 // Partition Driver Global Variables. 23 // 24 EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding = { 25 PartitionDriverBindingSupported, 26 PartitionDriverBindingStart, 27 PartitionDriverBindingStop, 28 // 29 // Grub4Dos copies the BPB of the first partition to the MBR. If the 30 // DriverBindingStart() of the Fat driver gets run before that of Partition 31 // driver only the first partition can be recognized. 32 // Let the driver binding version of Partition driver be higher than that of 33 // Fat driver to make sure the DriverBindingStart() of the Partition driver 34 // gets run before that of Fat driver so that all the partitions can be recognized. 35 // 36 0xb, 37 NULL, 38 NULL 39 }; 40 41 // 42 // Prioritized function list to detect partition table. 43 // 44 PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable[] = { 45 PartitionInstallGptChildHandles, 46 PartitionInstallElToritoChildHandles, 47 PartitionInstallMbrChildHandles, 48 NULL 49 }; 50 51 /** 52 Test to see if this driver supports ControllerHandle. Any ControllerHandle 53 than contains a BlockIo and DiskIo protocol or a BlockIo2 protocol can be 54 supported. 55 56 @param[in] This Protocol instance pointer. 57 @param[in] ControllerHandle Handle of device to test. 58 @param[in] RemainingDevicePath Optional parameter use to pick a specific child 59 device to start. 60 61 @retval EFI_SUCCESS This driver supports this device 62 @retval EFI_ALREADY_STARTED This driver is already running on this device 63 @retval other This driver does not support this device 64 65 **/ 66 EFI_STATUS 67 EFIAPI 68 PartitionDriverBindingSupported ( 69 IN EFI_DRIVER_BINDING_PROTOCOL *This, 70 IN EFI_HANDLE ControllerHandle, 71 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 72 ) 73 { 74 EFI_STATUS Status; 75 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; 76 EFI_DISK_IO_PROTOCOL *DiskIo; 77 EFI_DEV_PATH *Node; 78 79 // 80 // Check RemainingDevicePath validation 81 // 82 if (RemainingDevicePath != NULL) { 83 // 84 // Check if RemainingDevicePath is the End of Device Path Node, 85 // if yes, go on checking other conditions 86 // 87 if (!IsDevicePathEnd (RemainingDevicePath)) { 88 // 89 // If RemainingDevicePath isn't the End of Device Path Node, 90 // check its validation 91 // 92 Node = (EFI_DEV_PATH *) RemainingDevicePath; 93 if (Node->DevPath.Type != MEDIA_DEVICE_PATH || 94 Node->DevPath.SubType != MEDIA_HARDDRIVE_DP || 95 DevicePathNodeLength (&Node->DevPath) != sizeof (HARDDRIVE_DEVICE_PATH)) { 96 return EFI_UNSUPPORTED; 97 } 98 } 99 } 100 101 // 102 // Open the IO Abstraction(s) needed to perform the supported test 103 // 104 Status = gBS->OpenProtocol ( 105 ControllerHandle, 106 &gEfiDiskIoProtocolGuid, 107 (VOID **) &DiskIo, 108 This->DriverBindingHandle, 109 ControllerHandle, 110 EFI_OPEN_PROTOCOL_BY_DRIVER 111 ); 112 if (Status == EFI_ALREADY_STARTED) { 113 return EFI_SUCCESS; 114 } 115 if (EFI_ERROR (Status)) { 116 return Status; 117 } 118 // 119 // Close the I/O Abstraction(s) used to perform the supported test 120 // 121 gBS->CloseProtocol ( 122 ControllerHandle, 123 &gEfiDiskIoProtocolGuid, 124 This->DriverBindingHandle, 125 ControllerHandle 126 ); 127 128 // 129 // Open the EFI Device Path protocol needed to perform the supported test 130 // 131 Status = gBS->OpenProtocol ( 132 ControllerHandle, 133 &gEfiDevicePathProtocolGuid, 134 (VOID **) &ParentDevicePath, 135 This->DriverBindingHandle, 136 ControllerHandle, 137 EFI_OPEN_PROTOCOL_BY_DRIVER 138 ); 139 if (Status == EFI_ALREADY_STARTED) { 140 return EFI_SUCCESS; 141 } 142 143 if (EFI_ERROR (Status)) { 144 return Status; 145 } 146 147 // 148 // Close protocol, don't use device path protocol in the Support() function 149 // 150 gBS->CloseProtocol ( 151 ControllerHandle, 152 &gEfiDevicePathProtocolGuid, 153 This->DriverBindingHandle, 154 ControllerHandle 155 ); 156 157 // 158 // Open the IO Abstraction(s) needed to perform the supported test 159 // 160 Status = gBS->OpenProtocol ( 161 ControllerHandle, 162 &gEfiBlockIoProtocolGuid, 163 NULL, 164 This->DriverBindingHandle, 165 ControllerHandle, 166 EFI_OPEN_PROTOCOL_TEST_PROTOCOL 167 ); 168 169 return Status; 170 } 171 172 /** 173 Start this driver on ControllerHandle by opening a Block IO or a Block IO2 174 or both, and Disk IO protocol, reading Device Path, and creating a child 175 handle with a Disk IO and device path protocol. 176 177 @param[in] This Protocol instance pointer. 178 @param[in] ControllerHandle Handle of device to bind driver to 179 @param[in] RemainingDevicePath Optional parameter use to pick a specific child 180 device to start. 181 182 @retval EFI_SUCCESS This driver is added to ControllerHandle 183 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle 184 @retval other This driver does not support this device 185 186 **/ 187 EFI_STATUS 188 EFIAPI 189 PartitionDriverBindingStart ( 190 IN EFI_DRIVER_BINDING_PROTOCOL *This, 191 IN EFI_HANDLE ControllerHandle, 192 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 193 ) 194 { 195 EFI_STATUS Status; 196 EFI_STATUS OpenStatus; 197 EFI_BLOCK_IO_PROTOCOL *BlockIo; 198 EFI_BLOCK_IO2_PROTOCOL *BlockIo2; 199 EFI_DISK_IO_PROTOCOL *DiskIo; 200 EFI_DISK_IO2_PROTOCOL *DiskIo2; 201 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; 202 PARTITION_DETECT_ROUTINE *Routine; 203 BOOLEAN MediaPresent; 204 EFI_TPL OldTpl; 205 206 BlockIo2 = NULL; 207 OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 208 // 209 // Check RemainingDevicePath validation 210 // 211 if (RemainingDevicePath != NULL) { 212 // 213 // Check if RemainingDevicePath is the End of Device Path Node, 214 // if yes, return EFI_SUCCESS 215 // 216 if (IsDevicePathEnd (RemainingDevicePath)) { 217 Status = EFI_SUCCESS; 218 goto Exit; 219 } 220 } 221 222 // 223 // Try to open BlockIO and BlockIO2. If BlockIO would be opened, continue, 224 // otherwise, return error. 225 // 226 Status = gBS->OpenProtocol ( 227 ControllerHandle, 228 &gEfiBlockIoProtocolGuid, 229 (VOID **) &BlockIo, 230 This->DriverBindingHandle, 231 ControllerHandle, 232 EFI_OPEN_PROTOCOL_GET_PROTOCOL 233 ); 234 if (EFI_ERROR (Status)) { 235 goto Exit; 236 } 237 238 Status = gBS->OpenProtocol ( 239 ControllerHandle, 240 &gEfiBlockIo2ProtocolGuid, 241 (VOID **) &BlockIo2, 242 This->DriverBindingHandle, 243 ControllerHandle, 244 EFI_OPEN_PROTOCOL_GET_PROTOCOL 245 ); 246 if (EFI_ERROR (Status)) { 247 BlockIo2 = NULL; 248 } 249 250 // 251 // Get the Device Path Protocol on ControllerHandle's handle. 252 // 253 Status = gBS->OpenProtocol ( 254 ControllerHandle, 255 &gEfiDevicePathProtocolGuid, 256 (VOID **) &ParentDevicePath, 257 This->DriverBindingHandle, 258 ControllerHandle, 259 EFI_OPEN_PROTOCOL_BY_DRIVER 260 ); 261 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { 262 goto Exit; 263 } 264 265 // 266 // Get the DiskIo and DiskIo2. 267 // 268 Status = gBS->OpenProtocol ( 269 ControllerHandle, 270 &gEfiDiskIoProtocolGuid, 271 (VOID **) &DiskIo, 272 This->DriverBindingHandle, 273 ControllerHandle, 274 EFI_OPEN_PROTOCOL_BY_DRIVER 275 ); 276 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { 277 gBS->CloseProtocol ( 278 ControllerHandle, 279 &gEfiDevicePathProtocolGuid, 280 This->DriverBindingHandle, 281 ControllerHandle 282 ); 283 goto Exit; 284 } 285 286 OpenStatus = Status; 287 288 Status = gBS->OpenProtocol ( 289 ControllerHandle, 290 &gEfiDiskIo2ProtocolGuid, 291 (VOID **) &DiskIo2, 292 This->DriverBindingHandle, 293 ControllerHandle, 294 EFI_OPEN_PROTOCOL_BY_DRIVER 295 ); 296 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { 297 DiskIo2 = NULL; 298 } 299 300 // 301 // Try to read blocks when there's media or it is removable physical partition. 302 // 303 Status = EFI_UNSUPPORTED; 304 MediaPresent = BlockIo->Media->MediaPresent; 305 if (BlockIo->Media->MediaPresent || 306 (BlockIo->Media->RemovableMedia && !BlockIo->Media->LogicalPartition)) { 307 // 308 // Try for GPT, then El Torito, and then legacy MBR partition types. If the 309 // media supports a given partition type install child handles to represent 310 // the partitions described by the media. 311 // 312 Routine = &mPartitionDetectRoutineTable[0]; 313 while (*Routine != NULL) { 314 Status = (*Routine) ( 315 This, 316 ControllerHandle, 317 DiskIo, 318 DiskIo2, 319 BlockIo, 320 BlockIo2, 321 ParentDevicePath 322 ); 323 if (!EFI_ERROR (Status) || Status == EFI_MEDIA_CHANGED || Status == EFI_NO_MEDIA) { 324 break; 325 } 326 Routine++; 327 } 328 } 329 // 330 // In the case that the driver is already started (OpenStatus == EFI_ALREADY_STARTED), 331 // the DevicePathProtocol and the DiskIoProtocol are not actually opened by the 332 // driver. So don't try to close them. Otherwise, we will break the dependency 333 // between the controller and the driver set up before. 334 // 335 // In the case that when the media changes on a device it will Reinstall the 336 // BlockIo interaface. This will cause a call to our Stop(), and a subsequent 337 // reentrant call to our Start() successfully. We should leave the device open 338 // when this happen. The "media change" case includes either the status is 339 // EFI_MEDIA_CHANGED or it is a "media" to "no media" change. 340 // 341 if (EFI_ERROR (Status) && 342 !EFI_ERROR (OpenStatus) && 343 Status != EFI_MEDIA_CHANGED && 344 !(MediaPresent && Status == EFI_NO_MEDIA)) { 345 gBS->CloseProtocol ( 346 ControllerHandle, 347 &gEfiDiskIoProtocolGuid, 348 This->DriverBindingHandle, 349 ControllerHandle 350 ); 351 // 352 // Close Parent DiskIo2 if has. 353 // 354 gBS->CloseProtocol ( 355 ControllerHandle, 356 &gEfiDiskIo2ProtocolGuid, 357 This->DriverBindingHandle, 358 ControllerHandle 359 ); 360 361 gBS->CloseProtocol ( 362 ControllerHandle, 363 &gEfiDevicePathProtocolGuid, 364 This->DriverBindingHandle, 365 ControllerHandle 366 ); 367 } 368 369 Exit: 370 gBS->RestoreTPL (OldTpl); 371 return Status; 372 } 373 374 /** 375 Stop this driver on ControllerHandle. Support stopping any child handles 376 created by this driver. 377 378 @param This Protocol instance pointer. 379 @param ControllerHandle Handle of device to stop driver on 380 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of 381 children is zero stop the entire bus driver. 382 @param ChildHandleBuffer List of Child Handles to Stop. 383 384 @retval EFI_SUCCESS This driver is removed ControllerHandle 385 @retval other This driver was not removed from this device 386 387 **/ 388 EFI_STATUS 389 EFIAPI 390 PartitionDriverBindingStop ( 391 IN EFI_DRIVER_BINDING_PROTOCOL *This, 392 IN EFI_HANDLE ControllerHandle, 393 IN UINTN NumberOfChildren, 394 IN EFI_HANDLE *ChildHandleBuffer 395 ) 396 { 397 EFI_STATUS Status; 398 UINTN Index; 399 EFI_BLOCK_IO_PROTOCOL *BlockIo; 400 EFI_BLOCK_IO2_PROTOCOL *BlockIo2; 401 BOOLEAN AllChildrenStopped; 402 PARTITION_PRIVATE_DATA *Private; 403 EFI_DISK_IO_PROTOCOL *DiskIo; 404 405 BlockIo = NULL; 406 BlockIo2 = NULL; 407 Private = NULL; 408 409 if (NumberOfChildren == 0) { 410 // 411 // Close the bus driver 412 // 413 gBS->CloseProtocol ( 414 ControllerHandle, 415 &gEfiDiskIoProtocolGuid, 416 This->DriverBindingHandle, 417 ControllerHandle 418 ); 419 // 420 // Close Parent BlockIO2 if has. 421 // 422 gBS->CloseProtocol ( 423 ControllerHandle, 424 &gEfiDiskIo2ProtocolGuid, 425 This->DriverBindingHandle, 426 ControllerHandle 427 ); 428 429 gBS->CloseProtocol ( 430 ControllerHandle, 431 &gEfiDevicePathProtocolGuid, 432 This->DriverBindingHandle, 433 ControllerHandle 434 ); 435 return EFI_SUCCESS; 436 } 437 438 AllChildrenStopped = TRUE; 439 for (Index = 0; Index < NumberOfChildren; Index++) { 440 gBS->OpenProtocol ( 441 ChildHandleBuffer[Index], 442 &gEfiBlockIoProtocolGuid, 443 (VOID **) &BlockIo, 444 This->DriverBindingHandle, 445 ControllerHandle, 446 EFI_OPEN_PROTOCOL_GET_PROTOCOL 447 ); 448 // 449 // Try to locate BlockIo2. 450 // 451 gBS->OpenProtocol ( 452 ChildHandleBuffer[Index], 453 &gEfiBlockIo2ProtocolGuid, 454 (VOID **) &BlockIo2, 455 This->DriverBindingHandle, 456 ControllerHandle, 457 EFI_OPEN_PROTOCOL_GET_PROTOCOL 458 ); 459 460 461 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo); 462 463 Status = gBS->CloseProtocol ( 464 ControllerHandle, 465 &gEfiDiskIoProtocolGuid, 466 This->DriverBindingHandle, 467 ChildHandleBuffer[Index] 468 ); 469 // 470 // All Software protocols have be freed from the handle so remove it. 471 // Remove the BlockIo Protocol if has. 472 // Remove the BlockIo2 Protocol if has. 473 // 474 if (BlockIo2 != NULL) { 475 BlockIo->FlushBlocks (BlockIo); 476 BlockIo2->FlushBlocksEx (BlockIo2, NULL); 477 Status = gBS->UninstallMultipleProtocolInterfaces ( 478 ChildHandleBuffer[Index], 479 &gEfiDevicePathProtocolGuid, 480 Private->DevicePath, 481 &gEfiBlockIoProtocolGuid, 482 &Private->BlockIo, 483 &gEfiBlockIo2ProtocolGuid, 484 &Private->BlockIo2, 485 Private->EspGuid, 486 NULL, 487 NULL 488 ); 489 } else { 490 BlockIo->FlushBlocks (BlockIo); 491 Status = gBS->UninstallMultipleProtocolInterfaces ( 492 ChildHandleBuffer[Index], 493 &gEfiDevicePathProtocolGuid, 494 Private->DevicePath, 495 &gEfiBlockIoProtocolGuid, 496 &Private->BlockIo, 497 Private->EspGuid, 498 NULL, 499 NULL 500 ); 501 } 502 503 if (EFI_ERROR (Status)) { 504 gBS->OpenProtocol ( 505 ControllerHandle, 506 &gEfiDiskIoProtocolGuid, 507 (VOID **) &DiskIo, 508 This->DriverBindingHandle, 509 ChildHandleBuffer[Index], 510 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 511 ); 512 } else { 513 FreePool (Private->DevicePath); 514 FreePool (Private); 515 } 516 517 if (EFI_ERROR (Status)) { 518 AllChildrenStopped = FALSE; 519 } 520 } 521 522 if (!AllChildrenStopped) { 523 return EFI_DEVICE_ERROR; 524 } 525 526 return EFI_SUCCESS; 527 } 528 529 530 /** 531 Reset the Block Device. 532 533 @param This Protocol instance pointer. 534 @param ExtendedVerification Driver may perform diagnostics on reset. 535 536 @retval EFI_SUCCESS The device was reset. 537 @retval EFI_DEVICE_ERROR The device is not functioning properly and could 538 not be reset. 539 540 **/ 541 EFI_STATUS 542 EFIAPI 543 PartitionReset ( 544 IN EFI_BLOCK_IO_PROTOCOL *This, 545 IN BOOLEAN ExtendedVerification 546 ) 547 { 548 PARTITION_PRIVATE_DATA *Private; 549 550 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This); 551 552 return Private->ParentBlockIo->Reset ( 553 Private->ParentBlockIo, 554 ExtendedVerification 555 ); 556 } 557 558 /** 559 Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED 560 for no media or media change case. Otherwise DefaultStatus is returned. 561 562 @param DiskIo Pointer to the DiskIo instance. 563 @param MediaId Id of the media, changes every time the media is replaced. 564 @param DefaultStatus The default status to return when it's not the no media 565 or media change case. 566 567 @retval EFI_NO_MEDIA There is no media. 568 @retval EFI_MEDIA_CHANGED The media was changed. 569 @retval others The default status to return. 570 **/ 571 EFI_STATUS 572 ProbeMediaStatus ( 573 IN EFI_DISK_IO_PROTOCOL *DiskIo, 574 IN UINT32 MediaId, 575 IN EFI_STATUS DefaultStatus 576 ) 577 { 578 EFI_STATUS Status; 579 UINT8 Buffer[1]; 580 581 // 582 // Read 1 byte from offset 0 to check if the MediaId is still valid. 583 // The reading operation is synchronious thus it is not worth it to 584 // allocate a buffer from the pool. The destination buffer for the 585 // data is in the stack. 586 // 587 Status = DiskIo->ReadDisk (DiskIo, MediaId, 0, 1, (VOID*)Buffer); 588 if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) { 589 return Status; 590 } 591 return DefaultStatus; 592 } 593 594 /** 595 Read by using the Disk IO protocol on the parent device. Lba addresses 596 must be converted to byte offsets. 597 598 @param This Protocol instance pointer. 599 @param MediaId Id of the media, changes every time the media is replaced. 600 @param Lba The starting Logical Block Address to read from 601 @param BufferSize Size of Buffer, must be a multiple of device block size. 602 @param Buffer Buffer containing read data 603 604 @retval EFI_SUCCESS The data was read correctly from the device. 605 @retval EFI_DEVICE_ERROR The device reported an error while performing the read. 606 @retval EFI_NO_MEDIA There is no media in the device. 607 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device. 608 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device. 609 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not 610 valid for the device. 611 612 **/ 613 EFI_STATUS 614 EFIAPI 615 PartitionReadBlocks ( 616 IN EFI_BLOCK_IO_PROTOCOL *This, 617 IN UINT32 MediaId, 618 IN EFI_LBA Lba, 619 IN UINTN BufferSize, 620 OUT VOID *Buffer 621 ) 622 { 623 PARTITION_PRIVATE_DATA *Private; 624 UINT64 Offset; 625 626 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This); 627 628 if (BufferSize % Private->BlockSize != 0) { 629 return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE); 630 } 631 632 Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start; 633 if (Offset + BufferSize > Private->End) { 634 return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER); 635 } 636 // 637 // Because some kinds of partition have different block size from their parent 638 // device, we call the Disk IO protocol on the parent device, not the Block IO 639 // protocol 640 // 641 return Private->DiskIo->ReadDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer); 642 } 643 644 /** 645 Write by using the Disk IO protocol on the parent device. Lba addresses 646 must be converted to byte offsets. 647 648 @param[in] This Protocol instance pointer. 649 @param[in] MediaId Id of the media, changes every time the media is replaced. 650 @param[in] Lba The starting Logical Block Address to read from 651 @param[in] BufferSize Size of Buffer, must be a multiple of device block size. 652 @param[in] Buffer Buffer containing data to be written to device. 653 654 @retval EFI_SUCCESS The data was written correctly to the device. 655 @retval EFI_WRITE_PROTECTED The device can not be written to. 656 @retval EFI_DEVICE_ERROR The device reported an error while performing the write. 657 @retval EFI_NO_MEDIA There is no media in the device. 658 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device. 659 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device. 660 @retval EFI_INVALID_PARAMETER The write request contains a LBA that is not 661 valid for the device. 662 663 **/ 664 EFI_STATUS 665 EFIAPI 666 PartitionWriteBlocks ( 667 IN EFI_BLOCK_IO_PROTOCOL *This, 668 IN UINT32 MediaId, 669 IN EFI_LBA Lba, 670 IN UINTN BufferSize, 671 IN VOID *Buffer 672 ) 673 { 674 PARTITION_PRIVATE_DATA *Private; 675 UINT64 Offset; 676 677 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This); 678 679 if (BufferSize % Private->BlockSize != 0) { 680 return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE); 681 } 682 683 Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start; 684 if (Offset + BufferSize > Private->End) { 685 return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER); 686 } 687 // 688 // Because some kinds of partition have different block size from their parent 689 // device, we call the Disk IO protocol on the parent device, not the Block IO 690 // protocol 691 // 692 return Private->DiskIo->WriteDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer); 693 } 694 695 696 /** 697 Flush the parent Block Device. 698 699 @param This Protocol instance pointer. 700 701 @retval EFI_SUCCESS All outstanding data was written to the device 702 @retval EFI_DEVICE_ERROR The device reported an error while writting back the data 703 @retval EFI_NO_MEDIA There is no media in the device. 704 705 **/ 706 EFI_STATUS 707 EFIAPI 708 PartitionFlushBlocks ( 709 IN EFI_BLOCK_IO_PROTOCOL *This 710 ) 711 { 712 PARTITION_PRIVATE_DATA *Private; 713 714 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This); 715 716 return Private->ParentBlockIo->FlushBlocks (Private->ParentBlockIo); 717 } 718 719 /** 720 Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED 721 for no media or media change case. Otherwise DefaultStatus is returned. 722 723 @param DiskIo2 Pointer to the DiskIo2 instance. 724 @param MediaId Id of the media, changes every time the media is replaced. 725 @param DefaultStatus The default status to return when it's not the no media 726 or media change case. 727 728 @retval EFI_NO_MEDIA There is no media. 729 @retval EFI_MEDIA_CHANGED The media was changed. 730 @retval others The default status to return. 731 **/ 732 EFI_STATUS 733 ProbeMediaStatusEx ( 734 IN EFI_DISK_IO2_PROTOCOL *DiskIo2, 735 IN UINT32 MediaId, 736 IN EFI_STATUS DefaultStatus 737 ) 738 { 739 EFI_STATUS Status; 740 741 // 742 // Read 1 byte from offset 0 but passing NULL as buffer pointer 743 // 744 Status = DiskIo2->ReadDiskEx (DiskIo2, MediaId, 0, NULL, 1, NULL); 745 if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) { 746 return Status; 747 } 748 return DefaultStatus; 749 } 750 751 /** 752 Reset the Block Device throught Block I/O2 protocol. 753 754 @param This Protocol instance pointer. 755 @param ExtendedVerification Driver may perform diagnostics on reset. 756 757 @retval EFI_SUCCESS The device was reset. 758 @retval EFI_DEVICE_ERROR The device is not functioning properly and could 759 not be reset. 760 761 **/ 762 EFI_STATUS 763 EFIAPI 764 PartitionResetEx ( 765 IN EFI_BLOCK_IO2_PROTOCOL *This, 766 IN BOOLEAN ExtendedVerification 767 ) 768 { 769 PARTITION_PRIVATE_DATA *Private; 770 771 Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This); 772 773 return Private->ParentBlockIo2->Reset ( 774 Private->ParentBlockIo2, 775 ExtendedVerification 776 ); 777 } 778 779 /** 780 The general callback for the DiskIo2 interfaces. 781 @param Event Event whose notification function is being invoked. 782 @param Context The pointer to the notification function's context, 783 which points to the PARTITION_ACCESS_TASK instance. 784 **/ 785 VOID 786 EFIAPI 787 PartitionOnAccessComplete ( 788 IN EFI_EVENT Event, 789 IN VOID *Context 790 ) 791 { 792 PARTITION_ACCESS_TASK *Task; 793 794 Task = (PARTITION_ACCESS_TASK *) Context; 795 796 gBS->CloseEvent (Event); 797 798 Task->BlockIo2Token->TransactionStatus = Task->DiskIo2Token.TransactionStatus; 799 gBS->SignalEvent (Task->BlockIo2Token->Event); 800 801 FreePool (Task); 802 } 803 804 /** 805 Create a new PARTITION_ACCESS_TASK instance. 806 807 @param Token Pointer to the EFI_BLOCK_IO2_TOKEN. 808 809 @return Pointer to the created PARTITION_ACCESS_TASK instance or NULL upon failure. 810 **/ 811 PARTITION_ACCESS_TASK * 812 PartitionCreateAccessTask ( 813 IN EFI_BLOCK_IO2_TOKEN *Token 814 ) 815 { 816 EFI_STATUS Status; 817 PARTITION_ACCESS_TASK *Task; 818 819 Task = AllocatePool (sizeof (*Task)); 820 if (Task == NULL) { 821 return NULL; 822 } 823 824 Status = gBS->CreateEvent ( 825 EVT_NOTIFY_SIGNAL, 826 TPL_NOTIFY, 827 PartitionOnAccessComplete, 828 Task, 829 &Task->DiskIo2Token.Event 830 ); 831 if (EFI_ERROR (Status)) { 832 FreePool (Task); 833 return NULL; 834 } 835 836 Task->BlockIo2Token = Token; 837 838 return Task; 839 } 840 841 /** 842 Read BufferSize bytes from Lba into Buffer. 843 844 This function reads the requested number of blocks from the device. All the 845 blocks are read, or an error is returned. 846 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and 847 non-blocking I/O is being used, the Event associated with this request will 848 not be signaled. 849 850 @param[in] This Indicates a pointer to the calling context. 851 @param[in] MediaId Id of the media, changes every time the media is 852 replaced. 853 @param[in] Lba The starting Logical Block Address to read from. 854 @param[in, out] Token A pointer to the token associated with the transaction. 855 @param[in] BufferSize Size of Buffer, must be a multiple of device block size. 856 @param[out] Buffer A pointer to the destination buffer for the data. The 857 caller is responsible for either having implicit or 858 explicit ownership of the buffer. 859 860 @retval EFI_SUCCESS The read request was queued if Token->Event is 861 not NULL.The data was read correctly from the 862 device if the Token->Event is NULL. 863 @retval EFI_DEVICE_ERROR The device reported an error while performing 864 the read. 865 @retval EFI_NO_MEDIA There is no media in the device. 866 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. 867 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the 868 intrinsic block size of the device. 869 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, 870 or the buffer is not on proper alignment. 871 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack 872 of resources. 873 **/ 874 EFI_STATUS 875 EFIAPI 876 PartitionReadBlocksEx ( 877 IN EFI_BLOCK_IO2_PROTOCOL *This, 878 IN UINT32 MediaId, 879 IN EFI_LBA Lba, 880 IN OUT EFI_BLOCK_IO2_TOKEN *Token, 881 IN UINTN BufferSize, 882 OUT VOID *Buffer 883 ) 884 { 885 EFI_STATUS Status; 886 PARTITION_PRIVATE_DATA *Private; 887 UINT64 Offset; 888 PARTITION_ACCESS_TASK *Task; 889 890 Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This); 891 892 if (BufferSize % Private->BlockSize != 0) { 893 return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_BAD_BUFFER_SIZE); 894 } 895 896 Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start; 897 if (Offset + BufferSize > Private->End) { 898 return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_INVALID_PARAMETER); 899 } 900 901 if ((Token != NULL) && (Token->Event != NULL)) { 902 Task = PartitionCreateAccessTask (Token); 903 if (Task == NULL) { 904 return EFI_OUT_OF_RESOURCES; 905 } 906 907 Status = Private->DiskIo2->ReadDiskEx (Private->DiskIo2, MediaId, Offset, &Task->DiskIo2Token, BufferSize, Buffer); 908 if (EFI_ERROR (Status)) { 909 gBS->CloseEvent (Task->DiskIo2Token.Event); 910 FreePool (Task); 911 } 912 } else { 913 Status = Private->DiskIo2->ReadDiskEx (Private->DiskIo2, MediaId, Offset, NULL, BufferSize, Buffer); 914 } 915 916 return Status; 917 } 918 919 /** 920 Write BufferSize bytes from Lba into Buffer. 921 922 This function writes the requested number of blocks to the device. All blocks 923 are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA, 924 EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is 925 being used, the Event associated with this request will not be signaled. 926 927 @param[in] This Indicates a pointer to the calling context. 928 @param[in] MediaId The media ID that the write request is for. 929 @param[in] Lba The starting logical block address to be written. The 930 caller is responsible for writing to only legitimate 931 locations. 932 @param[in, out] Token A pointer to the token associated with the transaction. 933 @param[in] BufferSize Size of Buffer, must be a multiple of device block size. 934 @param[in] Buffer A pointer to the source buffer for the data. 935 936 @retval EFI_SUCCESS The write request was queued if Event is not NULL. 937 The data was written correctly to the device if 938 the Event is NULL. 939 @retval EFI_WRITE_PROTECTED The device can not be written to. 940 @retval EFI_NO_MEDIA There is no media in the device. 941 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device. 942 @retval EFI_DEVICE_ERROR The device reported an error while performing the write. 943 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device. 944 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, 945 or the buffer is not on proper alignment. 946 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack 947 of resources. 948 949 **/ 950 EFI_STATUS 951 EFIAPI 952 PartitionWriteBlocksEx ( 953 IN EFI_BLOCK_IO2_PROTOCOL *This, 954 IN UINT32 MediaId, 955 IN EFI_LBA Lba, 956 IN OUT EFI_BLOCK_IO2_TOKEN *Token, 957 IN UINTN BufferSize, 958 IN VOID *Buffer 959 ) 960 { 961 EFI_STATUS Status; 962 PARTITION_PRIVATE_DATA *Private; 963 UINT64 Offset; 964 PARTITION_ACCESS_TASK *Task; 965 966 Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This); 967 968 if (BufferSize % Private->BlockSize != 0) { 969 return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_BAD_BUFFER_SIZE); 970 } 971 972 Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start; 973 if (Offset + BufferSize > Private->End) { 974 return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_INVALID_PARAMETER); 975 } 976 977 if ((Token != NULL) && (Token->Event != NULL)) { 978 Task = PartitionCreateAccessTask (Token); 979 if (Task == NULL) { 980 return EFI_OUT_OF_RESOURCES; 981 } 982 983 Status = Private->DiskIo2->WriteDiskEx (Private->DiskIo2, MediaId, Offset, &Task->DiskIo2Token, BufferSize, Buffer); 984 if (EFI_ERROR (Status)) { 985 gBS->CloseEvent (Task->DiskIo2Token.Event); 986 FreePool (Task); 987 } 988 } else { 989 Status = Private->DiskIo2->WriteDiskEx (Private->DiskIo2, MediaId, Offset, NULL, BufferSize, Buffer); 990 } 991 return Status; 992 } 993 994 /** 995 Flush the Block Device. 996 997 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED 998 is returned and non-blocking I/O is being used, the Event associated with 999 this request will not be signaled. 1000 1001 @param[in] This Indicates a pointer to the calling context. 1002 @param[in, out] Token A pointer to the token associated with the transaction 1003 1004 @retval EFI_SUCCESS The flush request was queued if Event is not NULL. 1005 All outstanding data was written correctly to the 1006 device if the Event is NULL. 1007 @retval EFI_DEVICE_ERROR The device reported an error while writting back 1008 the data. 1009 @retval EFI_WRITE_PROTECTED The device cannot be written to. 1010 @retval EFI_NO_MEDIA There is no media in the device. 1011 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. 1012 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack 1013 of resources. 1014 1015 **/ 1016 EFI_STATUS 1017 EFIAPI 1018 PartitionFlushBlocksEx ( 1019 IN EFI_BLOCK_IO2_PROTOCOL *This, 1020 IN OUT EFI_BLOCK_IO2_TOKEN *Token 1021 ) 1022 { 1023 EFI_STATUS Status; 1024 PARTITION_PRIVATE_DATA *Private; 1025 PARTITION_ACCESS_TASK *Task; 1026 1027 Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This); 1028 1029 if ((Token != NULL) && (Token->Event != NULL)) { 1030 Task = PartitionCreateAccessTask (Token); 1031 if (Task == NULL) { 1032 return EFI_OUT_OF_RESOURCES; 1033 } 1034 1035 Status = Private->DiskIo2->FlushDiskEx (Private->DiskIo2, &Task->DiskIo2Token); 1036 if (EFI_ERROR (Status)) { 1037 gBS->CloseEvent (Task->DiskIo2Token.Event); 1038 FreePool (Task); 1039 } 1040 } else { 1041 Status = Private->DiskIo2->FlushDiskEx (Private->DiskIo2, NULL); 1042 } 1043 return Status; 1044 } 1045 1046 1047 /** 1048 Create a child handle for a logical block device that represents the 1049 bytes Start to End of the Parent Block IO device. 1050 1051 @param[in] This Protocol instance pointer. 1052 @param[in] ParentHandle Parent Handle for new child. 1053 @param[in] ParentDiskIo Parent DiskIo interface. 1054 @param[in] ParentDiskIo2 Parent DiskIo2 interface. 1055 @param[in] ParentBlockIo Parent BlockIo interface. 1056 @param[in] ParentBlockIo2 Parent BlockIo2 interface. 1057 @param[in] ParentDevicePath Parent Device Path. 1058 @param[in] DevicePathNode Child Device Path node. 1059 @param[in] Start Start Block. 1060 @param[in] End End Block. 1061 @param[in] BlockSize Child block size. 1062 @param[in] InstallEspGuid Flag to install EFI System Partition GUID on handle. 1063 1064 @retval EFI_SUCCESS A child handle was added. 1065 @retval other A child handle was not added. 1066 1067 **/ 1068 EFI_STATUS 1069 PartitionInstallChildHandle ( 1070 IN EFI_DRIVER_BINDING_PROTOCOL *This, 1071 IN EFI_HANDLE ParentHandle, 1072 IN EFI_DISK_IO_PROTOCOL *ParentDiskIo, 1073 IN EFI_DISK_IO2_PROTOCOL *ParentDiskIo2, 1074 IN EFI_BLOCK_IO_PROTOCOL *ParentBlockIo, 1075 IN EFI_BLOCK_IO2_PROTOCOL *ParentBlockIo2, 1076 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, 1077 IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, 1078 IN EFI_LBA Start, 1079 IN EFI_LBA End, 1080 IN UINT32 BlockSize, 1081 IN BOOLEAN InstallEspGuid 1082 ) 1083 { 1084 EFI_STATUS Status; 1085 PARTITION_PRIVATE_DATA *Private; 1086 1087 Status = EFI_SUCCESS; 1088 Private = AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA)); 1089 if (Private == NULL) { 1090 return EFI_OUT_OF_RESOURCES; 1091 } 1092 1093 Private->Signature = PARTITION_PRIVATE_DATA_SIGNATURE; 1094 1095 Private->Start = MultU64x32 (Start, ParentBlockIo->Media->BlockSize); 1096 Private->End = MultU64x32 (End + 1, ParentBlockIo->Media->BlockSize); 1097 1098 Private->BlockSize = BlockSize; 1099 Private->ParentBlockIo = ParentBlockIo; 1100 Private->ParentBlockIo2 = ParentBlockIo2; 1101 Private->DiskIo = ParentDiskIo; 1102 Private->DiskIo2 = ParentDiskIo2; 1103 1104 // 1105 // Set the BlockIO into Private Data. 1106 // 1107 Private->BlockIo.Revision = ParentBlockIo->Revision; 1108 1109 Private->BlockIo.Media = &Private->Media; 1110 CopyMem (Private->BlockIo.Media, ParentBlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA)); 1111 1112 Private->BlockIo.Reset = PartitionReset; 1113 Private->BlockIo.ReadBlocks = PartitionReadBlocks; 1114 Private->BlockIo.WriteBlocks = PartitionWriteBlocks; 1115 Private->BlockIo.FlushBlocks = PartitionFlushBlocks; 1116 1117 // 1118 // Set the BlockIO2 into Private Data. 1119 // 1120 if (Private->DiskIo2 != NULL) { 1121 ASSERT (Private->ParentBlockIo2 != NULL); 1122 Private->BlockIo2.Media = &Private->Media2; 1123 CopyMem (Private->BlockIo2.Media, ParentBlockIo2->Media, sizeof (EFI_BLOCK_IO_MEDIA)); 1124 1125 Private->BlockIo2.Reset = PartitionResetEx; 1126 Private->BlockIo2.ReadBlocksEx = PartitionReadBlocksEx; 1127 Private->BlockIo2.WriteBlocksEx = PartitionWriteBlocksEx; 1128 Private->BlockIo2.FlushBlocksEx = PartitionFlushBlocksEx; 1129 } 1130 1131 Private->Media.IoAlign = 0; 1132 Private->Media.LogicalPartition = TRUE; 1133 Private->Media.LastBlock = DivU64x32 ( 1134 MultU64x32 ( 1135 End - Start + 1, 1136 ParentBlockIo->Media->BlockSize 1137 ), 1138 BlockSize 1139 ) - 1; 1140 1141 Private->Media.BlockSize = (UINT32) BlockSize; 1142 1143 Private->Media2.IoAlign = 0; 1144 Private->Media2.LogicalPartition = TRUE; 1145 Private->Media2.LastBlock = Private->Media.LastBlock; 1146 Private->Media2.BlockSize = (UINT32) BlockSize; 1147 1148 // 1149 // Per UEFI Spec, LowestAlignedLba, LogicalBlocksPerPhysicalBlock and OptimalTransferLengthGranularity must be 0 1150 // for logical partitions. 1151 // 1152 if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION2) { 1153 Private->Media.LowestAlignedLba = 0; 1154 Private->Media.LogicalBlocksPerPhysicalBlock = 0; 1155 Private->Media2.LowestAlignedLba = 0; 1156 Private->Media2.LogicalBlocksPerPhysicalBlock = 0; 1157 if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION3) { 1158 Private->Media.OptimalTransferLengthGranularity = 0; 1159 Private->Media2.OptimalTransferLengthGranularity = 0; 1160 } 1161 } 1162 1163 Private->DevicePath = AppendDevicePathNode (ParentDevicePath, DevicePathNode); 1164 1165 if (Private->DevicePath == NULL) { 1166 FreePool (Private); 1167 return EFI_OUT_OF_RESOURCES; 1168 } 1169 1170 if (InstallEspGuid) { 1171 Private->EspGuid = &gEfiPartTypeSystemPartGuid; 1172 } else { 1173 // 1174 // If NULL InstallMultipleProtocolInterfaces will ignore it. 1175 // 1176 Private->EspGuid = NULL; 1177 } 1178 1179 // 1180 // Create the new handle. 1181 // 1182 Private->Handle = NULL; 1183 if (Private->DiskIo2 != NULL) { 1184 Status = gBS->InstallMultipleProtocolInterfaces ( 1185 &Private->Handle, 1186 &gEfiDevicePathProtocolGuid, 1187 Private->DevicePath, 1188 &gEfiBlockIoProtocolGuid, 1189 &Private->BlockIo, 1190 &gEfiBlockIo2ProtocolGuid, 1191 &Private->BlockIo2, 1192 Private->EspGuid, 1193 NULL, 1194 NULL 1195 ); 1196 } else { 1197 Status = gBS->InstallMultipleProtocolInterfaces ( 1198 &Private->Handle, 1199 &gEfiDevicePathProtocolGuid, 1200 Private->DevicePath, 1201 &gEfiBlockIoProtocolGuid, 1202 &Private->BlockIo, 1203 Private->EspGuid, 1204 NULL, 1205 NULL 1206 ); 1207 } 1208 1209 if (!EFI_ERROR (Status)) { 1210 // 1211 // Open the Parent Handle for the child 1212 // 1213 Status = gBS->OpenProtocol ( 1214 ParentHandle, 1215 &gEfiDiskIoProtocolGuid, 1216 (VOID **) &ParentDiskIo, 1217 This->DriverBindingHandle, 1218 Private->Handle, 1219 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 1220 ); 1221 } else { 1222 FreePool (Private->DevicePath); 1223 FreePool (Private); 1224 } 1225 1226 return Status; 1227 } 1228 1229 1230 /** 1231 The user Entry Point for module Partition. The user code starts with this function. 1232 1233 @param[in] ImageHandle The firmware allocated handle for the EFI image. 1234 @param[in] SystemTable A pointer to the EFI System Table. 1235 1236 @retval EFI_SUCCESS The entry point is executed successfully. 1237 @retval other Some error occurs when executing this entry point. 1238 1239 **/ 1240 EFI_STATUS 1241 EFIAPI 1242 InitializePartition ( 1243 IN EFI_HANDLE ImageHandle, 1244 IN EFI_SYSTEM_TABLE *SystemTable 1245 ) 1246 { 1247 EFI_STATUS Status; 1248 1249 // 1250 // Install driver model protocol(s). 1251 // 1252 Status = EfiLibInstallDriverBindingComponentName2 ( 1253 ImageHandle, 1254 SystemTable, 1255 &gPartitionDriverBinding, 1256 ImageHandle, 1257 &gPartitionComponentName, 1258 &gPartitionComponentName2 1259 ); 1260 ASSERT_EFI_ERROR (Status); 1261 1262 1263 return Status; 1264 } 1265 1266