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.
7 Copyright (c) 2006 - 2011, 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
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.
19 #include "Partition.h"
22 // Partition Driver Global Variables.
24 EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding
= {
25 PartitionDriverBindingSupported
,
26 PartitionDriverBindingStart
,
27 PartitionDriverBindingStop
,
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.
42 // Prioritized function list to detect partition table.
44 PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable
[] = {
45 PartitionInstallGptChildHandles
,
46 PartitionInstallElToritoChildHandles
,
47 PartitionInstallMbrChildHandles
,
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
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
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
68 PartitionDriverBindingSupported (
69 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
70 IN EFI_HANDLE ControllerHandle
,
71 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
75 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
76 EFI_DISK_IO_PROTOCOL
*DiskIo
;
80 // Check RemainingDevicePath validation
82 if (RemainingDevicePath
!= NULL
) {
84 // Check if RemainingDevicePath is the End of Device Path Node,
85 // if yes, go on checking other conditions
87 if (!IsDevicePathEnd (RemainingDevicePath
)) {
89 // If RemainingDevicePath isn't the End of Device Path Node,
90 // check its validation
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
;
102 // Open the IO Abstraction(s) needed to perform the supported test
104 Status
= gBS
->OpenProtocol (
106 &gEfiDiskIoProtocolGuid
,
108 This
->DriverBindingHandle
,
110 EFI_OPEN_PROTOCOL_BY_DRIVER
112 if (Status
== EFI_ALREADY_STARTED
) {
115 if (EFI_ERROR (Status
)) {
119 // Close the I/O Abstraction(s) used to perform the supported test
123 &gEfiDiskIoProtocolGuid
,
124 This
->DriverBindingHandle
,
129 // Open the EFI Device Path protocol needed to perform the supported test
131 Status
= gBS
->OpenProtocol (
133 &gEfiDevicePathProtocolGuid
,
134 (VOID
**) &ParentDevicePath
,
135 This
->DriverBindingHandle
,
137 EFI_OPEN_PROTOCOL_BY_DRIVER
139 if (Status
== EFI_ALREADY_STARTED
) {
143 if (EFI_ERROR (Status
)) {
148 // Close protocol, don't use device path protocol in the Support() function
152 &gEfiDevicePathProtocolGuid
,
153 This
->DriverBindingHandle
,
158 // Open the IO Abstraction(s) needed to perform the supported test
160 Status
= gBS
->OpenProtocol (
162 &gEfiBlockIoProtocolGuid
,
164 This
->DriverBindingHandle
,
166 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
168 if (EFI_ERROR (Status
)) {
176 Start this driver on ControllerHandle by opening a Block IO or a Block IO2
177 or both, and Disk IO protocol, reading Device Path, and creating a child
178 handle with a Disk IO and device path protocol.
180 @param[in] This Protocol instance pointer.
181 @param[in] ControllerHandle Handle of device to bind driver to
182 @param[in] RemainingDevicePath Optional parameter use to pick a specific child
185 @retval EFI_SUCCESS This driver is added to ControllerHandle
186 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
187 @retval other This driver does not support this device
192 PartitionDriverBindingStart (
193 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
194 IN EFI_HANDLE ControllerHandle
,
195 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
199 EFI_STATUS OpenStatus
;
200 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
201 EFI_BLOCK_IO2_PROTOCOL
*BlockIo2
;
202 EFI_DISK_IO_PROTOCOL
*DiskIo
;
203 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
204 PARTITION_DETECT_ROUTINE
*Routine
;
205 BOOLEAN MediaPresent
;
209 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
211 // Check RemainingDevicePath validation
213 if (RemainingDevicePath
!= NULL
) {
215 // Check if RemainingDevicePath is the End of Device Path Node,
216 // if yes, return EFI_SUCCESS
218 if (IsDevicePathEnd (RemainingDevicePath
)) {
219 Status
= EFI_SUCCESS
;
225 // Try to open BlockIO and BlockIO2. If BlockIO would be opened, continue,
226 // otherwise, return error.
228 Status
= gBS
->OpenProtocol (
230 &gEfiBlockIoProtocolGuid
,
232 This
->DriverBindingHandle
,
234 EFI_OPEN_PROTOCOL_GET_PROTOCOL
236 if (EFI_ERROR (Status
)) {
240 Status
= gBS
->OpenProtocol (
242 &gEfiBlockIo2ProtocolGuid
,
244 This
->DriverBindingHandle
,
246 EFI_OPEN_PROTOCOL_BY_DRIVER
250 // Get the Device Path Protocol on ControllerHandle's handle.
252 Status
= gBS
->OpenProtocol (
254 &gEfiDevicePathProtocolGuid
,
255 (VOID
**) &ParentDevicePath
,
256 This
->DriverBindingHandle
,
258 EFI_OPEN_PROTOCOL_BY_DRIVER
260 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
264 Status
= gBS
->OpenProtocol (
266 &gEfiDiskIoProtocolGuid
,
268 This
->DriverBindingHandle
,
270 EFI_OPEN_PROTOCOL_BY_DRIVER
272 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
275 &gEfiDevicePathProtocolGuid
,
276 This
->DriverBindingHandle
,
285 // Try to read blocks when there's media or it is removable physical partition.
287 Status
= EFI_UNSUPPORTED
;
288 MediaPresent
= BlockIo
->Media
->MediaPresent
;
289 if (BlockIo
->Media
->MediaPresent
||
290 (BlockIo
->Media
->RemovableMedia
&& !BlockIo
->Media
->LogicalPartition
)) {
292 // Try for GPT, then El Torito, and then legacy MBR partition types. If the
293 // media supports a given partition type install child handles to represent
294 // the partitions described by the media.
296 Routine
= &mPartitionDetectRoutineTable
[0];
297 while (*Routine
!= NULL
) {
298 Status
= (*Routine
) (
306 if (!EFI_ERROR (Status
) || Status
== EFI_MEDIA_CHANGED
|| Status
== EFI_NO_MEDIA
) {
313 // In the case that the driver is already started (OpenStatus == EFI_ALREADY_STARTED),
314 // the DevicePathProtocol and the DiskIoProtocol are not actually opened by the
315 // driver. So don't try to close them. Otherwise, we will break the dependency
316 // between the controller and the driver set up before.
318 // In the case that when the media changes on a device it will Reinstall the
319 // BlockIo interaface. This will cause a call to our Stop(), and a subsequent
320 // reentrant call to our Start() successfully. We should leave the device open
321 // when this happen. The "media change" case includes either the status is
322 // EFI_MEDIA_CHANGED or it is a "media" to "no media" change.
324 if (EFI_ERROR (Status
) &&
325 !EFI_ERROR (OpenStatus
) &&
326 Status
!= EFI_MEDIA_CHANGED
&&
327 !(MediaPresent
&& Status
== EFI_NO_MEDIA
)) {
330 &gEfiDiskIoProtocolGuid
,
331 This
->DriverBindingHandle
,
335 // Close Parent BlockIO2 if has.
339 &gEfiBlockIo2ProtocolGuid
,
340 This
->DriverBindingHandle
,
346 &gEfiDevicePathProtocolGuid
,
347 This
->DriverBindingHandle
,
353 gBS
->RestoreTPL (OldTpl
);
358 Stop this driver on ControllerHandle. Support stopping any child handles
359 created by this driver.
361 @param This Protocol instance pointer.
362 @param ControllerHandle Handle of device to stop driver on
363 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
364 children is zero stop the entire bus driver.
365 @param ChildHandleBuffer List of Child Handles to Stop.
367 @retval EFI_SUCCESS This driver is removed ControllerHandle
368 @retval other This driver was not removed from this device
373 PartitionDriverBindingStop (
374 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
375 IN EFI_HANDLE ControllerHandle
,
376 IN UINTN NumberOfChildren
,
377 IN EFI_HANDLE
*ChildHandleBuffer
382 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
383 EFI_BLOCK_IO2_PROTOCOL
*BlockIo2
;
384 BOOLEAN AllChildrenStopped
;
385 PARTITION_PRIVATE_DATA
*Private
;
386 EFI_DISK_IO_PROTOCOL
*DiskIo
;
392 if (NumberOfChildren
== 0) {
394 // Close the bus driver
398 &gEfiDiskIoProtocolGuid
,
399 This
->DriverBindingHandle
,
403 // Close Parent BlockIO2 if has.
407 &gEfiBlockIo2ProtocolGuid
,
408 This
->DriverBindingHandle
,
414 &gEfiDevicePathProtocolGuid
,
415 This
->DriverBindingHandle
,
421 AllChildrenStopped
= TRUE
;
422 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
424 ChildHandleBuffer
[Index
],
425 &gEfiBlockIoProtocolGuid
,
427 This
->DriverBindingHandle
,
429 EFI_OPEN_PROTOCOL_GET_PROTOCOL
432 // Try to locate BlockIo2.
435 ChildHandleBuffer
[Index
],
436 &gEfiBlockIo2ProtocolGuid
,
438 This
->DriverBindingHandle
,
440 EFI_OPEN_PROTOCOL_GET_PROTOCOL
444 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo
);
446 Status
= gBS
->CloseProtocol (
448 &gEfiDiskIoProtocolGuid
,
449 This
->DriverBindingHandle
,
450 ChildHandleBuffer
[Index
]
453 // All Software protocols have be freed from the handle so remove it.
454 // Remove the BlockIo Protocol if has.
455 // Remove the BlockIo2 Protocol if has.
457 if (BlockIo2
!= NULL
) {
458 BlockIo
->FlushBlocks (BlockIo
);
459 BlockIo2
->FlushBlocksEx (BlockIo2
, NULL
);
460 Status
= gBS
->UninstallMultipleProtocolInterfaces (
461 ChildHandleBuffer
[Index
],
462 &gEfiDevicePathProtocolGuid
,
464 &gEfiBlockIoProtocolGuid
,
466 &gEfiBlockIo2ProtocolGuid
,
473 BlockIo
->FlushBlocks (BlockIo
);
474 Status
= gBS
->UninstallMultipleProtocolInterfaces (
475 ChildHandleBuffer
[Index
],
476 &gEfiDevicePathProtocolGuid
,
478 &gEfiBlockIoProtocolGuid
,
486 if (EFI_ERROR (Status
)) {
489 &gEfiDiskIoProtocolGuid
,
491 This
->DriverBindingHandle
,
492 ChildHandleBuffer
[Index
],
493 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
496 FreePool (Private
->DevicePath
);
500 if (EFI_ERROR (Status
)) {
501 AllChildrenStopped
= FALSE
;
505 if (!AllChildrenStopped
) {
506 return EFI_DEVICE_ERROR
;
514 Reset the Block Device.
516 @param This Protocol instance pointer.
517 @param ExtendedVerification Driver may perform diagnostics on reset.
519 @retval EFI_SUCCESS The device was reset.
520 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
527 IN EFI_BLOCK_IO_PROTOCOL
*This
,
528 IN BOOLEAN ExtendedVerification
531 PARTITION_PRIVATE_DATA
*Private
;
533 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
535 return Private
->ParentBlockIo
->Reset (
536 Private
->ParentBlockIo
,
542 Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED
543 for no media or media change case. Otherwise DefaultStatus is returned.
545 @param DiskIo Pointer to the DiskIo instance.
546 @param MediaId Id of the media, changes every time the media is replaced.
547 @param DefaultStatus The default status to return when it's not the no media
548 or media change case.
550 @retval EFI_NO_MEDIA There is no media.
551 @retval EFI_MEDIA_CHANGED The media was changed.
552 @retval others The default status to return.
556 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
558 IN EFI_STATUS DefaultStatus
564 // Read 1 byte from offset 0 but passing NULL as buffer pointer
566 Status
= DiskIo
->ReadDisk (DiskIo
, MediaId
, 0, 1, NULL
);
567 if ((Status
== EFI_NO_MEDIA
) || (Status
== EFI_MEDIA_CHANGED
)) {
570 return DefaultStatus
;
574 Read by using the Disk IO protocol on the parent device. Lba addresses
575 must be converted to byte offsets.
577 @param This Protocol instance pointer.
578 @param MediaId Id of the media, changes every time the media is replaced.
579 @param Lba The starting Logical Block Address to read from
580 @param BufferSize Size of Buffer, must be a multiple of device block size.
581 @param Buffer Buffer containing read data
583 @retval EFI_SUCCESS The data was read correctly from the device.
584 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
585 @retval EFI_NO_MEDIA There is no media in the device.
586 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
587 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
588 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
589 valid for the device.
594 PartitionReadBlocks (
595 IN EFI_BLOCK_IO_PROTOCOL
*This
,
602 PARTITION_PRIVATE_DATA
*Private
;
605 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
607 if (BufferSize
% Private
->BlockSize
!= 0) {
608 return ProbeMediaStatus (Private
->DiskIo
, MediaId
, EFI_BAD_BUFFER_SIZE
);
611 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
612 if (Offset
+ BufferSize
> Private
->End
) {
613 return ProbeMediaStatus (Private
->DiskIo
, MediaId
, EFI_INVALID_PARAMETER
);
616 // Because some kinds of partition have different block size from their parent
617 // device, we call the Disk IO protocol on the parent device, not the Block IO
620 return Private
->DiskIo
->ReadDisk (Private
->DiskIo
, MediaId
, Offset
, BufferSize
, Buffer
);
624 Write by using the Disk IO protocol on the parent device. Lba addresses
625 must be converted to byte offsets.
627 @param[in] This Protocol instance pointer.
628 @param[in] MediaId Id of the media, changes every time the media is replaced.
629 @param[in] Lba The starting Logical Block Address to read from
630 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
631 @param[in] Buffer Buffer containing data to be written to device.
633 @retval EFI_SUCCESS The data was written correctly to the device.
634 @retval EFI_WRITE_PROTECTED The device can not be written to.
635 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
636 @retval EFI_NO_MEDIA There is no media in the device.
637 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
638 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
639 @retval EFI_INVALID_PARAMETER The write request contains a LBA that is not
640 valid for the device.
645 PartitionWriteBlocks (
646 IN EFI_BLOCK_IO_PROTOCOL
*This
,
653 PARTITION_PRIVATE_DATA
*Private
;
656 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
658 if (BufferSize
% Private
->BlockSize
!= 0) {
659 return ProbeMediaStatus (Private
->DiskIo
, MediaId
, EFI_BAD_BUFFER_SIZE
);
662 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
663 if (Offset
+ BufferSize
> Private
->End
) {
664 return ProbeMediaStatus (Private
->DiskIo
, MediaId
, EFI_INVALID_PARAMETER
);
667 // Because some kinds of partition have different block size from their parent
668 // device, we call the Disk IO protocol on the parent device, not the Block IO
671 return Private
->DiskIo
->WriteDisk (Private
->DiskIo
, MediaId
, Offset
, BufferSize
, Buffer
);
676 Flush the parent Block Device.
678 @param This Protocol instance pointer.
680 @retval EFI_SUCCESS All outstanding data was written to the device
681 @retval EFI_DEVICE_ERROR The device reported an error while writting back the data
682 @retval EFI_NO_MEDIA There is no media in the device.
687 PartitionFlushBlocks (
688 IN EFI_BLOCK_IO_PROTOCOL
*This
691 PARTITION_PRIVATE_DATA
*Private
;
693 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
695 return Private
->ParentBlockIo
->FlushBlocks (Private
->ParentBlockIo
);
699 Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED
700 for no media or media change case. Otherwise DefaultStatus is returned.
702 @param BlockIo2 Pointer to the BlockIo2 instance.
703 @param MediaId Id of the media, changes every time the media is replaced.
704 @param DefaultStatus The default status to return when it's not the no media
705 or media change case.
707 @retval EFI_NO_MEDIA There is no media.
708 @retval EFI_MEDIA_CHANGED The media was changed.
709 @retval others The default status to return.
713 IN EFI_BLOCK_IO2_PROTOCOL
*BlockIo2
,
715 IN EFI_STATUS DefaultStatus
721 // Read from LBA 0 but passing NULL as buffer pointer to detect the media status.
723 Status
= BlockIo2
->ReadBlocksEx (
731 if ((Status
== EFI_NO_MEDIA
) || (Status
== EFI_MEDIA_CHANGED
)) {
734 return DefaultStatus
;
738 Reset the Block Device throught Block I/O2 protocol.
740 @param This Protocol instance pointer.
741 @param ExtendedVerification Driver may perform diagnostics on reset.
743 @retval EFI_SUCCESS The device was reset.
744 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
751 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
752 IN BOOLEAN ExtendedVerification
755 PARTITION_PRIVATE_DATA
*Private
;
757 Private
= PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This
);
759 return Private
->ParentBlockIo2
->Reset (
760 Private
->ParentBlockIo2
,
766 Read BufferSize bytes from Lba into Buffer.
768 This function reads the requested number of blocks from the device. All the
769 blocks are read, or an error is returned.
770 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and
771 non-blocking I/O is being used, the Event associated with this request will
774 @param[in] This Indicates a pointer to the calling context.
775 @param[in] MediaId Id of the media, changes every time the media is
777 @param[in] Lba The starting Logical Block Address to read from.
778 @param[in, out] Token A pointer to the token associated with the transaction.
779 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
780 @param[out] Buffer A pointer to the destination buffer for the data. The
781 caller is responsible for either having implicit or
782 explicit ownership of the buffer.
784 @retval EFI_SUCCESS The read request was queued if Token->Event is
785 not NULL.The data was read correctly from the
786 device if the Token->Event is NULL.
787 @retval EFI_DEVICE_ERROR The device reported an error while performing
789 @retval EFI_NO_MEDIA There is no media in the device.
790 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
791 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
792 intrinsic block size of the device.
793 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
794 or the buffer is not on proper alignment.
795 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
800 PartitionReadBlocksEx (
801 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
804 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
809 PARTITION_PRIVATE_DATA
*Private
;
813 Private
= PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This
);
816 return ProbeMediaStatusEx (Private
->ParentBlockIo2
, MediaId
, EFI_INVALID_PARAMETER
);
819 if (BufferSize
% Private
->BlockSize
!= 0) {
820 return ProbeMediaStatusEx (Private
->ParentBlockIo2
, MediaId
, EFI_BAD_BUFFER_SIZE
);
823 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
824 if (Offset
+ BufferSize
> Private
->End
) {
825 return ProbeMediaStatusEx (Private
->ParentBlockIo2
, MediaId
, EFI_INVALID_PARAMETER
);
829 // Since the BlockIO2 call Parent BlockIO2 directly, so here the offset must
830 // be multiple of BlockSize. If the Spec will be updated the DiskIO to support
831 // BlockIO2, this limitation will be removed and call DiskIO here.
833 Lba
= DivU64x32Remainder (Offset
, Private
->BlockSize
, &UnderRun
);
835 return ProbeMediaStatusEx (Private
->ParentBlockIo2
, MediaId
, EFI_UNSUPPORTED
);
839 // Because some partitions have different block size from their parent
840 // device, in that case the Block I/O2 couldn't be called.
842 if (Private
->BlockSize
!= Private
->ParentBlockIo
->Media
->BlockSize
) {
843 return ProbeMediaStatusEx (Private
->ParentBlockIo2
, MediaId
, EFI_UNSUPPORTED
);
846 return Private
->ParentBlockIo2
->ReadBlocksEx (Private
->ParentBlockIo2
, MediaId
, Lba
, Token
, BufferSize
, Buffer
);
850 Write BufferSize bytes from Lba into Buffer.
852 This function writes the requested number of blocks to the device. All blocks
853 are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
854 EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
855 being used, the Event associated with this request will not be signaled.
857 @param[in] This Indicates a pointer to the calling context.
858 @param[in] MediaId The media ID that the write request is for.
859 @param[in] Lba The starting logical block address to be written. The
860 caller is responsible for writing to only legitimate
862 @param[in, out] Token A pointer to the token associated with the transaction.
863 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
864 @param[in] Buffer A pointer to the source buffer for the data.
866 @retval EFI_SUCCESS The write request was queued if Event is not NULL.
867 The data was written correctly to the device if
869 @retval EFI_WRITE_PROTECTED The device can not be written to.
870 @retval EFI_NO_MEDIA There is no media in the device.
871 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
872 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
873 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
874 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
875 or the buffer is not on proper alignment.
876 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
882 PartitionWriteBlocksEx (
883 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
886 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
891 PARTITION_PRIVATE_DATA
*Private
;
895 Private
= PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This
);
898 return ProbeMediaStatusEx (Private
->ParentBlockIo2
, MediaId
, EFI_INVALID_PARAMETER
);
901 if (BufferSize
% Private
->BlockSize
!= 0) {
902 return ProbeMediaStatusEx (Private
->ParentBlockIo2
, MediaId
, EFI_BAD_BUFFER_SIZE
);
905 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
906 if (Offset
+ BufferSize
> Private
->End
) {
907 return ProbeMediaStatusEx (Private
->ParentBlockIo2
, MediaId
, EFI_INVALID_PARAMETER
);
911 // Since the BlockIO2 call Parent BlockIO2 directly, so here the offset must
912 // be multiple of BlockSize. If the Spec will be updated the DiskIO to support
913 // BlockIO2, this limitation will be removed and call DiskIO here.
915 Lba
= DivU64x32Remainder (Offset
, Private
->BlockSize
, &UnderRun
);
917 return ProbeMediaStatusEx (Private
->ParentBlockIo2
, MediaId
, EFI_UNSUPPORTED
);
921 // Because some kinds of partition have different block size from their parent,
922 // in that case it couldn't call parent Block I/O2.
924 if (Private
->BlockSize
!= Private
->ParentBlockIo
->Media
->BlockSize
) {
925 return ProbeMediaStatusEx (Private
->ParentBlockIo2
, MediaId
, EFI_UNSUPPORTED
);
928 return Private
->ParentBlockIo2
->WriteBlocksEx (Private
->ParentBlockIo2
, MediaId
, Lba
, Token
, BufferSize
, Buffer
);
932 Flush the Block Device.
934 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED
935 is returned and non-blocking I/O is being used, the Event associated with
936 this request will not be signaled.
938 @param[in] This Indicates a pointer to the calling context.
939 @param[in, out] Token A pointer to the token associated with the transaction
941 @retval EFI_SUCCESS The flush request was queued if Event is not NULL.
942 All outstanding data was written correctly to the
943 device if the Event is NULL.
944 @retval EFI_DEVICE_ERROR The device reported an error while writting back
946 @retval EFI_WRITE_PROTECTED The device cannot be written to.
947 @retval EFI_NO_MEDIA There is no media in the device.
948 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
949 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
955 PartitionFlushBlocksEx (
956 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
957 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
960 PARTITION_PRIVATE_DATA
*Private
;
962 Private
= PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This
);
965 // Because some kinds of partition have different block size from their parent,
966 // in that case it couldn't call parent Block I/O2.
968 if (Private
->BlockSize
!= Private
->ParentBlockIo
->Media
->BlockSize
) {
969 return EFI_UNSUPPORTED
;
972 return Private
->ParentBlockIo2
->FlushBlocksEx (Private
->ParentBlockIo2
, Token
);
977 Create a child handle for a logical block device that represents the
978 bytes Start to End of the Parent Block IO device.
980 @param[in] This Protocol instance pointer.
981 @param[in] ParentHandle Parent Handle for new child.
982 @param[in] ParentDiskIo Parent DiskIo interface.
983 @param[in] ParentBlockIo Parent BlockIo interface.
984 @param[in] ParentBlockIo2 Parent BlockIo2 interface.
985 @param[in] ParentDevicePath Parent Device Path.
986 @param[in] DevicePathNode Child Device Path node.
987 @param[in] Start Start Block.
988 @param[in] End End Block.
989 @param[in] BlockSize Child block size.
990 @param[in] InstallEspGuid Flag to install EFI System Partition GUID on handle.
992 @retval EFI_SUCCESS A child handle was added.
993 @retval other A child handle was not added.
997 PartitionInstallChildHandle (
998 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
999 IN EFI_HANDLE ParentHandle
,
1000 IN EFI_DISK_IO_PROTOCOL
*ParentDiskIo
,
1001 IN EFI_BLOCK_IO_PROTOCOL
*ParentBlockIo
,
1002 IN EFI_BLOCK_IO2_PROTOCOL
*ParentBlockIo2
,
1003 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
1004 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
,
1007 IN UINT32 BlockSize
,
1008 IN BOOLEAN InstallEspGuid
1012 PARTITION_PRIVATE_DATA
*Private
;
1014 Status
= EFI_SUCCESS
;
1015 Private
= AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA
));
1016 if (Private
== NULL
) {
1017 return EFI_OUT_OF_RESOURCES
;
1020 Private
->Signature
= PARTITION_PRIVATE_DATA_SIGNATURE
;
1022 Private
->Start
= MultU64x32 (Start
, ParentBlockIo
->Media
->BlockSize
);
1023 Private
->End
= MultU64x32 (End
+ 1, ParentBlockIo
->Media
->BlockSize
);
1025 Private
->BlockSize
= BlockSize
;
1026 Private
->ParentBlockIo
= ParentBlockIo
;
1027 Private
->ParentBlockIo2
= ParentBlockIo2
;
1028 Private
->DiskIo
= ParentDiskIo
;
1031 // Set the BlockIO into Private Data.
1033 Private
->BlockIo
.Revision
= ParentBlockIo
->Revision
;
1035 Private
->BlockIo
.Media
= &Private
->Media
;
1036 CopyMem (Private
->BlockIo
.Media
, ParentBlockIo
->Media
, sizeof (EFI_BLOCK_IO_MEDIA
));
1038 Private
->BlockIo
.Reset
= PartitionReset
;
1039 Private
->BlockIo
.ReadBlocks
= PartitionReadBlocks
;
1040 Private
->BlockIo
.WriteBlocks
= PartitionWriteBlocks
;
1041 Private
->BlockIo
.FlushBlocks
= PartitionFlushBlocks
;
1044 // Set the BlockIO2 into Private Data.
1046 if (Private
->ParentBlockIo2
!= NULL
) {
1047 Private
->BlockIo2
.Media
= &Private
->Media2
;
1048 CopyMem (Private
->BlockIo2
.Media
, ParentBlockIo2
->Media
, sizeof (EFI_BLOCK_IO_MEDIA
));
1050 Private
->BlockIo2
.Reset
= PartitionResetEx
;
1051 Private
->BlockIo2
.ReadBlocksEx
= PartitionReadBlocksEx
;
1052 Private
->BlockIo2
.WriteBlocksEx
= PartitionWriteBlocksEx
;
1053 Private
->BlockIo2
.FlushBlocksEx
= PartitionFlushBlocksEx
;
1056 Private
->Media
.IoAlign
= 0;
1057 Private
->Media
.LogicalPartition
= TRUE
;
1058 Private
->Media
.LastBlock
= DivU64x32 (
1061 ParentBlockIo
->Media
->BlockSize
1066 Private
->Media
.BlockSize
= (UINT32
) BlockSize
;
1069 // For BlockIO2, it should keep the same alignment with the parent BlockIO2's.
1071 Private
->Media2
.LogicalPartition
= TRUE
;
1072 Private
->Media2
.LastBlock
= Private
->Media
.LastBlock
;
1073 Private
->Media2
.BlockSize
= (UINT32
) BlockSize
;
1076 // Per UEFI Spec, LowestAlignedLba, LogicalBlocksPerPhysicalBlock and OptimalTransferLengthGranularity must be 0
1077 // for logical partitions.
1079 if (Private
->BlockIo
.Revision
>= EFI_BLOCK_IO_PROTOCOL_REVISION2
) {
1080 Private
->Media
.LowestAlignedLba
= 0;
1081 Private
->Media
.LogicalBlocksPerPhysicalBlock
= 0;
1082 Private
->Media2
.LowestAlignedLba
= 0;
1083 Private
->Media2
.LogicalBlocksPerPhysicalBlock
= 0;
1084 if (Private
->BlockIo
.Revision
>= EFI_BLOCK_IO_PROTOCOL_REVISION3
) {
1085 Private
->Media
.OptimalTransferLengthGranularity
= 0;
1086 Private
->Media2
.OptimalTransferLengthGranularity
= 0;
1090 Private
->DevicePath
= AppendDevicePathNode (ParentDevicePath
, DevicePathNode
);
1092 if (Private
->DevicePath
== NULL
) {
1094 return EFI_OUT_OF_RESOURCES
;
1097 if (InstallEspGuid
) {
1098 Private
->EspGuid
= &gEfiPartTypeSystemPartGuid
;
1101 // If NULL InstallMultipleProtocolInterfaces will ignore it.
1103 Private
->EspGuid
= NULL
;
1107 // Create the new handle.
1108 // BlockIO2 will be installed on the condition that the blocksize of parent BlockIO
1109 // is same with the child BlockIO's. Instead of calling the DiskIO, the child BlockIO2
1110 // directly call the parent BlockIO and doesn't handle the different block size issue.
1111 // If SPEC will update the DiskIO to support the Non-Blocking model, the BlockIO2 will call
1112 // DiskIO to handle the blocksize unequal issue and the limitation will be remove from
1115 Private
->Handle
= NULL
;
1116 if ((Private
->ParentBlockIo2
!= NULL
) &&
1117 (Private
->ParentBlockIo2
->Media
->BlockSize
== BlockSize
)
1119 Status
= gBS
->InstallMultipleProtocolInterfaces (
1121 &gEfiDevicePathProtocolGuid
,
1122 Private
->DevicePath
,
1123 &gEfiBlockIoProtocolGuid
,
1125 &gEfiBlockIo2ProtocolGuid
,
1132 Status
= gBS
->InstallMultipleProtocolInterfaces (
1134 &gEfiDevicePathProtocolGuid
,
1135 Private
->DevicePath
,
1136 &gEfiBlockIoProtocolGuid
,
1144 if (!EFI_ERROR (Status
)) {
1146 // Open the Parent Handle for the child
1148 Status
= gBS
->OpenProtocol (
1150 &gEfiDiskIoProtocolGuid
,
1151 (VOID
**) &ParentDiskIo
,
1152 This
->DriverBindingHandle
,
1154 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1157 FreePool (Private
->DevicePath
);
1166 The user Entry Point for module Partition. The user code starts with this function.
1168 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1169 @param[in] SystemTable A pointer to the EFI System Table.
1171 @retval EFI_SUCCESS The entry point is executed successfully.
1172 @retval other Some error occurs when executing this entry point.
1177 InitializePartition (
1178 IN EFI_HANDLE ImageHandle
,
1179 IN EFI_SYSTEM_TABLE
*SystemTable
1185 // Install driver model protocol(s).
1187 Status
= EfiLibInstallDriverBindingComponentName2 (
1190 &gPartitionDriverBinding
,
1192 &gPartitionComponentName
,
1193 &gPartitionComponentName2
1195 ASSERT_EFI_ERROR (Status
);