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", UDF, Legacy
5 MBR, and GPT partition schemes are supported.
7 Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
8 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
9 SPDX-License-Identifier: BSD-2-Clause-Patent
13 #include "Partition.h"
16 // Partition Driver Global Variables.
18 EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding
= {
19 PartitionDriverBindingSupported
,
20 PartitionDriverBindingStart
,
21 PartitionDriverBindingStop
,
23 // Grub4Dos copies the BPB of the first partition to the MBR. If the
24 // DriverBindingStart() of the Fat driver gets run before that of Partition
25 // driver only the first partition can be recognized.
26 // Let the driver binding version of Partition driver be higher than that of
27 // Fat driver to make sure the DriverBindingStart() of the Partition driver
28 // gets run before that of Fat driver so that all the partitions can be recognized.
36 // Prioritized function list to detect partition table.
37 // Refer to UEFI Spec 13.3.2 Partition Discovery, the block device
38 // should be scanned in below order:
40 // 2. ISO 9660 (El Torito) (or UDF)
42 // 4. no partiton found
43 // Note: UDF is using a same method as booting from CD-ROM, so put it along
46 PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable
[] = {
47 PartitionInstallGptChildHandles
,
48 PartitionInstallUdfChildHandles
,
49 PartitionInstallMbrChildHandles
,
54 Test to see if this driver supports ControllerHandle. Any ControllerHandle
55 than contains a BlockIo and DiskIo protocol or a BlockIo2 protocol can be
58 @param[in] This Protocol instance pointer.
59 @param[in] ControllerHandle Handle of device to test.
60 @param[in] RemainingDevicePath Optional parameter use to pick a specific child
63 @retval EFI_SUCCESS This driver supports this device
64 @retval EFI_ALREADY_STARTED This driver is already running on this device
65 @retval other This driver does not support this device
70 PartitionDriverBindingSupported (
71 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
72 IN EFI_HANDLE ControllerHandle
,
73 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
77 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
78 EFI_DISK_IO_PROTOCOL
*DiskIo
;
82 // Check RemainingDevicePath validation
84 if (RemainingDevicePath
!= NULL
) {
86 // Check if RemainingDevicePath is the End of Device Path Node,
87 // if yes, go on checking other conditions
89 if (!IsDevicePathEnd (RemainingDevicePath
)) {
91 // If RemainingDevicePath isn't the End of Device Path Node,
92 // check its validation
94 Node
= (EFI_DEV_PATH
*)RemainingDevicePath
;
95 if ((Node
->DevPath
.Type
!= MEDIA_DEVICE_PATH
) ||
96 (Node
->DevPath
.SubType
!= MEDIA_HARDDRIVE_DP
) ||
97 (DevicePathNodeLength (&Node
->DevPath
) != sizeof (HARDDRIVE_DEVICE_PATH
)))
99 return EFI_UNSUPPORTED
;
105 // Open the IO Abstraction(s) needed to perform the supported test
107 Status
= gBS
->OpenProtocol (
109 &gEfiDiskIoProtocolGuid
,
111 This
->DriverBindingHandle
,
113 EFI_OPEN_PROTOCOL_BY_DRIVER
115 if (Status
== EFI_ALREADY_STARTED
) {
119 if (EFI_ERROR (Status
)) {
124 // Close the I/O Abstraction(s) used to perform the supported test
128 &gEfiDiskIoProtocolGuid
,
129 This
->DriverBindingHandle
,
134 // Open the EFI Device Path protocol needed to perform the supported test
136 Status
= gBS
->OpenProtocol (
138 &gEfiDevicePathProtocolGuid
,
139 (VOID
**)&ParentDevicePath
,
140 This
->DriverBindingHandle
,
142 EFI_OPEN_PROTOCOL_BY_DRIVER
144 if (Status
== EFI_ALREADY_STARTED
) {
148 if (EFI_ERROR (Status
)) {
153 // Close protocol, don't use device path protocol in the Support() function
157 &gEfiDevicePathProtocolGuid
,
158 This
->DriverBindingHandle
,
163 // Open the IO Abstraction(s) needed to perform the supported test
165 Status
= gBS
->OpenProtocol (
167 &gEfiBlockIoProtocolGuid
,
169 This
->DriverBindingHandle
,
171 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
178 Start this driver on ControllerHandle by opening a Block IO or a Block IO2
179 or both, and Disk IO protocol, reading Device Path, and creating a child
180 handle with a Disk IO and device path protocol.
182 @param[in] This Protocol instance pointer.
183 @param[in] ControllerHandle Handle of device to bind driver to
184 @param[in] RemainingDevicePath Optional parameter use to pick a specific child
187 @retval EFI_SUCCESS This driver is added to ControllerHandle
188 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
189 @retval other This driver does not support this device
194 PartitionDriverBindingStart (
195 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
196 IN EFI_HANDLE ControllerHandle
,
197 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
201 EFI_STATUS OpenStatus
;
202 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
203 EFI_BLOCK_IO2_PROTOCOL
*BlockIo2
;
204 EFI_DISK_IO_PROTOCOL
*DiskIo
;
205 EFI_DISK_IO2_PROTOCOL
*DiskIo2
;
206 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
207 PARTITION_DETECT_ROUTINE
*Routine
;
208 BOOLEAN MediaPresent
;
212 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
214 // Check RemainingDevicePath validation
216 if (RemainingDevicePath
!= NULL
) {
218 // Check if RemainingDevicePath is the End of Device Path Node,
219 // if yes, return EFI_SUCCESS
221 if (IsDevicePathEnd (RemainingDevicePath
)) {
222 Status
= EFI_SUCCESS
;
228 // Try to open BlockIO and BlockIO2. If BlockIO would be opened, continue,
229 // otherwise, return error.
231 Status
= gBS
->OpenProtocol (
233 &gEfiBlockIoProtocolGuid
,
235 This
->DriverBindingHandle
,
237 EFI_OPEN_PROTOCOL_GET_PROTOCOL
239 if (EFI_ERROR (Status
)) {
243 Status
= gBS
->OpenProtocol (
245 &gEfiBlockIo2ProtocolGuid
,
247 This
->DriverBindingHandle
,
249 EFI_OPEN_PROTOCOL_GET_PROTOCOL
251 if (EFI_ERROR (Status
)) {
256 // Get the Device Path Protocol on ControllerHandle's handle.
258 Status
= gBS
->OpenProtocol (
260 &gEfiDevicePathProtocolGuid
,
261 (VOID
**)&ParentDevicePath
,
262 This
->DriverBindingHandle
,
264 EFI_OPEN_PROTOCOL_BY_DRIVER
266 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
271 // Get the DiskIo and DiskIo2.
273 Status
= gBS
->OpenProtocol (
275 &gEfiDiskIoProtocolGuid
,
277 This
->DriverBindingHandle
,
279 EFI_OPEN_PROTOCOL_BY_DRIVER
281 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
284 &gEfiDevicePathProtocolGuid
,
285 This
->DriverBindingHandle
,
293 Status
= gBS
->OpenProtocol (
295 &gEfiDiskIo2ProtocolGuid
,
297 This
->DriverBindingHandle
,
299 EFI_OPEN_PROTOCOL_BY_DRIVER
301 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
306 // Try to read blocks when there's media or it is removable physical partition.
308 Status
= EFI_UNSUPPORTED
;
309 MediaPresent
= BlockIo
->Media
->MediaPresent
;
310 if (BlockIo
->Media
->MediaPresent
||
311 (BlockIo
->Media
->RemovableMedia
&& !BlockIo
->Media
->LogicalPartition
))
314 // Try for GPT, then legacy MBR partition types, and then UDF and El Torito.
315 // If the media supports a given partition type install child handles to
316 // represent the partitions described by the media.
318 Routine
= &mPartitionDetectRoutineTable
[0];
319 while (*Routine
!= NULL
) {
329 if (!EFI_ERROR (Status
) || (Status
== EFI_MEDIA_CHANGED
) || (Status
== EFI_NO_MEDIA
)) {
338 // In the case that the driver is already started (OpenStatus == EFI_ALREADY_STARTED),
339 // the DevicePathProtocol and the DiskIoProtocol are not actually opened by the
340 // driver. So don't try to close them. Otherwise, we will break the dependency
341 // between the controller and the driver set up before.
343 // In the case that when the media changes on a device it will Reinstall the
344 // BlockIo interaface. This will cause a call to our Stop(), and a subsequent
345 // reentrant call to our Start() successfully. We should leave the device open
346 // when this happen. The "media change" case includes either the status is
347 // EFI_MEDIA_CHANGED or it is a "media" to "no media" change.
349 if (EFI_ERROR (Status
) &&
350 !EFI_ERROR (OpenStatus
) &&
351 (Status
!= EFI_MEDIA_CHANGED
) &&
352 !(MediaPresent
&& (Status
== EFI_NO_MEDIA
)))
356 &gEfiDiskIoProtocolGuid
,
357 This
->DriverBindingHandle
,
361 // Close Parent DiskIo2 if has.
365 &gEfiDiskIo2ProtocolGuid
,
366 This
->DriverBindingHandle
,
372 &gEfiDevicePathProtocolGuid
,
373 This
->DriverBindingHandle
,
379 gBS
->RestoreTPL (OldTpl
);
384 Stop this driver on ControllerHandle. Support stopping any child handles
385 created by this driver.
387 @param This Protocol instance pointer.
388 @param ControllerHandle Handle of device to stop driver on
389 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
390 children is zero stop the entire bus driver.
391 @param ChildHandleBuffer List of Child Handles to Stop.
393 @retval EFI_SUCCESS This driver is removed ControllerHandle
394 @retval other This driver was not removed from this device
399 PartitionDriverBindingStop (
400 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
401 IN EFI_HANDLE ControllerHandle
,
402 IN UINTN NumberOfChildren
,
403 IN EFI_HANDLE
*ChildHandleBuffer
408 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
409 EFI_BLOCK_IO2_PROTOCOL
*BlockIo2
;
410 BOOLEAN AllChildrenStopped
;
411 PARTITION_PRIVATE_DATA
*Private
;
412 EFI_DISK_IO_PROTOCOL
*DiskIo
;
419 if (NumberOfChildren
== 0) {
421 // In the case of re-entry of the PartitionDriverBindingStop, the
422 // NumberOfChildren may not reflect the actual number of children on the
423 // bus driver. Hence, additional check is needed here.
425 if (HasChildren (ControllerHandle
)) {
426 DEBUG ((DEBUG_ERROR
, "PartitionDriverBindingStop: Still has child.\n"));
427 return EFI_DEVICE_ERROR
;
431 // Close the bus driver
435 &gEfiDiskIoProtocolGuid
,
436 This
->DriverBindingHandle
,
440 // Close Parent BlockIO2 if has.
444 &gEfiDiskIo2ProtocolGuid
,
445 This
->DriverBindingHandle
,
451 &gEfiDevicePathProtocolGuid
,
452 This
->DriverBindingHandle
,
458 AllChildrenStopped
= TRUE
;
459 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
461 ChildHandleBuffer
[Index
],
462 &gEfiBlockIoProtocolGuid
,
464 This
->DriverBindingHandle
,
466 EFI_OPEN_PROTOCOL_GET_PROTOCOL
469 // Try to locate BlockIo2.
472 ChildHandleBuffer
[Index
],
473 &gEfiBlockIo2ProtocolGuid
,
475 This
->DriverBindingHandle
,
477 EFI_OPEN_PROTOCOL_GET_PROTOCOL
480 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo
);
481 if (Private
->InStop
) {
483 // If the child handle is going to be stopped again during the re-entry
484 // of DriverBindingStop, just do nothing.
489 Private
->InStop
= TRUE
;
491 BlockIo
->FlushBlocks (BlockIo
);
493 if (BlockIo2
!= NULL
) {
494 Status
= BlockIo2
->FlushBlocksEx (BlockIo2
, NULL
);
495 DEBUG ((DEBUG_ERROR
, "PartitionDriverBindingStop: FlushBlocksEx returned with %r\n", Status
));
497 Status
= EFI_SUCCESS
;
502 &gEfiDiskIoProtocolGuid
,
503 This
->DriverBindingHandle
,
504 ChildHandleBuffer
[Index
]
507 if (IsZeroGuid (&Private
->TypeGuid
)) {
510 TypeGuid
= &Private
->TypeGuid
;
514 // All Software protocols have be freed from the handle so remove it.
515 // Remove the BlockIo Protocol if has.
516 // Remove the BlockIo2 Protocol if has.
518 if (BlockIo2
!= NULL
) {
520 // Some device drivers might re-install the BlockIO(2) protocols for a
521 // media change condition. Therefore, if the FlushBlocksEx returned with
522 // EFI_MEDIA_CHANGED, just let the BindingStop fail to avoid potential
523 // reference of already stopped child handle.
525 if (Status
!= EFI_MEDIA_CHANGED
) {
526 Status
= gBS
->UninstallMultipleProtocolInterfaces (
527 ChildHandleBuffer
[Index
],
528 &gEfiDevicePathProtocolGuid
,
530 &gEfiBlockIoProtocolGuid
,
532 &gEfiBlockIo2ProtocolGuid
,
534 &gEfiPartitionInfoProtocolGuid
,
535 &Private
->PartitionInfo
,
542 Status
= gBS
->UninstallMultipleProtocolInterfaces (
543 ChildHandleBuffer
[Index
],
544 &gEfiDevicePathProtocolGuid
,
546 &gEfiBlockIoProtocolGuid
,
548 &gEfiPartitionInfoProtocolGuid
,
549 &Private
->PartitionInfo
,
556 if (EFI_ERROR (Status
)) {
557 Private
->InStop
= FALSE
;
560 &gEfiDiskIoProtocolGuid
,
562 This
->DriverBindingHandle
,
563 ChildHandleBuffer
[Index
],
564 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
567 FreePool (Private
->DevicePath
);
571 if (EFI_ERROR (Status
)) {
572 AllChildrenStopped
= FALSE
;
573 if (Status
== EFI_MEDIA_CHANGED
) {
579 if (!AllChildrenStopped
) {
580 return EFI_DEVICE_ERROR
;
587 Reset the Block Device.
589 @param This Protocol instance pointer.
590 @param ExtendedVerification Driver may perform diagnostics on reset.
592 @retval EFI_SUCCESS The device was reset.
593 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
600 IN EFI_BLOCK_IO_PROTOCOL
*This
,
601 IN BOOLEAN ExtendedVerification
604 PARTITION_PRIVATE_DATA
*Private
;
606 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
608 return Private
->ParentBlockIo
->Reset (
609 Private
->ParentBlockIo
,
615 Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED
616 for no media or media change case. Otherwise DefaultStatus is returned.
618 @param DiskIo Pointer to the DiskIo instance.
619 @param MediaId Id of the media, changes every time the media is replaced.
620 @param DefaultStatus The default status to return when it's not the no media
621 or media change case.
623 @retval EFI_NO_MEDIA There is no media.
624 @retval EFI_MEDIA_CHANGED The media was changed.
625 @retval others The default status to return.
629 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
631 IN EFI_STATUS DefaultStatus
638 // Read 1 byte from offset 0 to check if the MediaId is still valid.
639 // The reading operation is synchronious thus it is not worth it to
640 // allocate a buffer from the pool. The destination buffer for the
641 // data is in the stack.
643 Status
= DiskIo
->ReadDisk (DiskIo
, MediaId
, 0, 1, (VOID
*)Buffer
);
644 if ((Status
== EFI_NO_MEDIA
) || (Status
== EFI_MEDIA_CHANGED
)) {
648 return DefaultStatus
;
652 Read by using the Disk IO protocol on the parent device. Lba addresses
653 must be converted to byte offsets.
655 @param This Protocol instance pointer.
656 @param MediaId Id of the media, changes every time the media is replaced.
657 @param Lba The starting Logical Block Address to read from
658 @param BufferSize Size of Buffer, must be a multiple of device block size.
659 @param Buffer Buffer containing read data
661 @retval EFI_SUCCESS The data was read correctly from the device.
662 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
663 @retval EFI_NO_MEDIA There is no media in the device.
664 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
665 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
666 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
667 valid for the device.
672 PartitionReadBlocks (
673 IN EFI_BLOCK_IO_PROTOCOL
*This
,
680 PARTITION_PRIVATE_DATA
*Private
;
683 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
685 if (BufferSize
% Private
->BlockSize
!= 0) {
686 return ProbeMediaStatus (Private
->DiskIo
, MediaId
, EFI_BAD_BUFFER_SIZE
);
689 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
690 if (Offset
+ BufferSize
> Private
->End
) {
691 return ProbeMediaStatus (Private
->DiskIo
, MediaId
, EFI_INVALID_PARAMETER
);
695 // Because some kinds of partition have different block size from their parent
696 // device, we call the Disk IO protocol on the parent device, not the Block IO
699 return Private
->DiskIo
->ReadDisk (Private
->DiskIo
, MediaId
, Offset
, BufferSize
, Buffer
);
703 Write by using the Disk IO protocol on the parent device. Lba addresses
704 must be converted to byte offsets.
706 @param[in] This Protocol instance pointer.
707 @param[in] MediaId Id of the media, changes every time the media is replaced.
708 @param[in] Lba The starting Logical Block Address to read from
709 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
710 @param[in] Buffer Buffer containing data to be written to device.
712 @retval EFI_SUCCESS The data was written correctly to the device.
713 @retval EFI_WRITE_PROTECTED The device can not be written to.
714 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
715 @retval EFI_NO_MEDIA There is no media in the device.
716 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
717 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
718 @retval EFI_INVALID_PARAMETER The write request contains a LBA that is not
719 valid for the device.
724 PartitionWriteBlocks (
725 IN EFI_BLOCK_IO_PROTOCOL
*This
,
732 PARTITION_PRIVATE_DATA
*Private
;
735 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
737 if (BufferSize
% Private
->BlockSize
!= 0) {
738 return ProbeMediaStatus (Private
->DiskIo
, MediaId
, EFI_BAD_BUFFER_SIZE
);
741 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
742 if (Offset
+ BufferSize
> Private
->End
) {
743 return ProbeMediaStatus (Private
->DiskIo
, MediaId
, EFI_INVALID_PARAMETER
);
747 // Because some kinds of partition have different block size from their parent
748 // device, we call the Disk IO protocol on the parent device, not the Block IO
751 return Private
->DiskIo
->WriteDisk (Private
->DiskIo
, MediaId
, Offset
, BufferSize
, Buffer
);
755 Flush the parent Block Device.
757 @param This Protocol instance pointer.
759 @retval EFI_SUCCESS All outstanding data was written to the device
760 @retval EFI_DEVICE_ERROR The device reported an error while writting back the data
761 @retval EFI_NO_MEDIA There is no media in the device.
766 PartitionFlushBlocks (
767 IN EFI_BLOCK_IO_PROTOCOL
*This
770 PARTITION_PRIVATE_DATA
*Private
;
772 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
774 return Private
->ParentBlockIo
->FlushBlocks (Private
->ParentBlockIo
);
778 Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED
779 for no media or media change case. Otherwise DefaultStatus is returned.
781 @param DiskIo2 Pointer to the DiskIo2 instance.
782 @param MediaId Id of the media, changes every time the media is replaced.
783 @param DefaultStatus The default status to return when it's not the no media
784 or media change case.
786 @retval EFI_NO_MEDIA There is no media.
787 @retval EFI_MEDIA_CHANGED The media was changed.
788 @retval others The default status to return.
792 IN EFI_DISK_IO2_PROTOCOL
*DiskIo2
,
794 IN EFI_STATUS DefaultStatus
801 // Read 1 byte from offset 0 to check if the MediaId is still valid.
802 // The reading operation is synchronious thus it is not worth it to
803 // allocate a buffer from the pool. The destination buffer for the
804 // data is in the stack.
806 Status
= DiskIo2
->ReadDiskEx (DiskIo2
, MediaId
, 0, NULL
, 1, (VOID
*)Buffer
);
807 if ((Status
== EFI_NO_MEDIA
) || (Status
== EFI_MEDIA_CHANGED
)) {
811 return DefaultStatus
;
815 Reset the Block Device throught Block I/O2 protocol.
817 @param This Protocol instance pointer.
818 @param ExtendedVerification Driver may perform diagnostics on reset.
820 @retval EFI_SUCCESS The device was reset.
821 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
828 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
829 IN BOOLEAN ExtendedVerification
832 PARTITION_PRIVATE_DATA
*Private
;
834 Private
= PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This
);
836 return Private
->ParentBlockIo2
->Reset (
837 Private
->ParentBlockIo2
,
843 The general callback for the DiskIo2 interfaces.
844 @param Event Event whose notification function is being invoked.
845 @param Context The pointer to the notification function's context,
846 which points to the PARTITION_ACCESS_TASK instance.
850 PartitionOnAccessComplete (
855 PARTITION_ACCESS_TASK
*Task
;
857 Task
= (PARTITION_ACCESS_TASK
*)Context
;
859 gBS
->CloseEvent (Event
);
861 Task
->BlockIo2Token
->TransactionStatus
= Task
->DiskIo2Token
.TransactionStatus
;
862 gBS
->SignalEvent (Task
->BlockIo2Token
->Event
);
868 Create a new PARTITION_ACCESS_TASK instance.
870 @param Token Pointer to the EFI_BLOCK_IO2_TOKEN.
872 @return Pointer to the created PARTITION_ACCESS_TASK instance or NULL upon failure.
874 PARTITION_ACCESS_TASK
*
875 PartitionCreateAccessTask (
876 IN EFI_BLOCK_IO2_TOKEN
*Token
880 PARTITION_ACCESS_TASK
*Task
;
882 Task
= AllocatePool (sizeof (*Task
));
887 Status
= gBS
->CreateEvent (
890 PartitionOnAccessComplete
,
892 &Task
->DiskIo2Token
.Event
894 if (EFI_ERROR (Status
)) {
899 Task
->BlockIo2Token
= Token
;
905 Read BufferSize bytes from Lba into Buffer.
907 This function reads the requested number of blocks from the device. All the
908 blocks are read, or an error is returned.
909 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and
910 non-blocking I/O is being used, the Event associated with this request will
913 @param[in] This Indicates a pointer to the calling context.
914 @param[in] MediaId Id of the media, changes every time the media is
916 @param[in] Lba The starting Logical Block Address to read from.
917 @param[in, out] Token A pointer to the token associated with the transaction.
918 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
919 @param[out] Buffer A pointer to the destination buffer for the data. The
920 caller is responsible for either having implicit or
921 explicit ownership of the buffer.
923 @retval EFI_SUCCESS The read request was queued if Token->Event is
924 not NULL.The data was read correctly from the
925 device if the Token->Event is NULL.
926 @retval EFI_DEVICE_ERROR The device reported an error while performing
928 @retval EFI_NO_MEDIA There is no media in the device.
929 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
930 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
931 intrinsic block size of the device.
932 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
933 or the buffer is not on proper alignment.
934 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
939 PartitionReadBlocksEx (
940 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
943 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
949 PARTITION_PRIVATE_DATA
*Private
;
951 PARTITION_ACCESS_TASK
*Task
;
953 Private
= PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This
);
955 if (BufferSize
% Private
->BlockSize
!= 0) {
956 return ProbeMediaStatusEx (Private
->DiskIo2
, MediaId
, EFI_BAD_BUFFER_SIZE
);
959 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
960 if (Offset
+ BufferSize
> Private
->End
) {
961 return ProbeMediaStatusEx (Private
->DiskIo2
, MediaId
, EFI_INVALID_PARAMETER
);
964 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
965 Task
= PartitionCreateAccessTask (Token
);
967 return EFI_OUT_OF_RESOURCES
;
970 Status
= Private
->DiskIo2
->ReadDiskEx (Private
->DiskIo2
, MediaId
, Offset
, &Task
->DiskIo2Token
, BufferSize
, Buffer
);
971 if (EFI_ERROR (Status
)) {
972 gBS
->CloseEvent (Task
->DiskIo2Token
.Event
);
976 Status
= Private
->DiskIo2
->ReadDiskEx (Private
->DiskIo2
, MediaId
, Offset
, NULL
, BufferSize
, Buffer
);
983 Write BufferSize bytes from Lba into Buffer.
985 This function writes the requested number of blocks to the device. All blocks
986 are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
987 EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
988 being used, the Event associated with this request will not be signaled.
990 @param[in] This Indicates a pointer to the calling context.
991 @param[in] MediaId The media ID that the write request is for.
992 @param[in] Lba The starting logical block address to be written. The
993 caller is responsible for writing to only legitimate
995 @param[in, out] Token A pointer to the token associated with the transaction.
996 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
997 @param[in] Buffer A pointer to the source buffer for the data.
999 @retval EFI_SUCCESS The write request was queued if Event is not NULL.
1000 The data was written correctly to the device if
1002 @retval EFI_WRITE_PROTECTED The device can not be written to.
1003 @retval EFI_NO_MEDIA There is no media in the device.
1004 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
1005 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
1006 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
1007 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
1008 or the buffer is not on proper alignment.
1009 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
1015 PartitionWriteBlocksEx (
1016 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
1019 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
1020 IN UINTN BufferSize
,
1025 PARTITION_PRIVATE_DATA
*Private
;
1027 PARTITION_ACCESS_TASK
*Task
;
1029 Private
= PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This
);
1031 if (BufferSize
% Private
->BlockSize
!= 0) {
1032 return ProbeMediaStatusEx (Private
->DiskIo2
, MediaId
, EFI_BAD_BUFFER_SIZE
);
1035 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
1036 if (Offset
+ BufferSize
> Private
->End
) {
1037 return ProbeMediaStatusEx (Private
->DiskIo2
, MediaId
, EFI_INVALID_PARAMETER
);
1040 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1041 Task
= PartitionCreateAccessTask (Token
);
1043 return EFI_OUT_OF_RESOURCES
;
1046 Status
= Private
->DiskIo2
->WriteDiskEx (Private
->DiskIo2
, MediaId
, Offset
, &Task
->DiskIo2Token
, BufferSize
, Buffer
);
1047 if (EFI_ERROR (Status
)) {
1048 gBS
->CloseEvent (Task
->DiskIo2Token
.Event
);
1052 Status
= Private
->DiskIo2
->WriteDiskEx (Private
->DiskIo2
, MediaId
, Offset
, NULL
, BufferSize
, Buffer
);
1059 Flush the Block Device.
1061 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED
1062 is returned and non-blocking I/O is being used, the Event associated with
1063 this request will not be signaled.
1065 @param[in] This Indicates a pointer to the calling context.
1066 @param[in, out] Token A pointer to the token associated with the transaction
1068 @retval EFI_SUCCESS The flush request was queued if Event is not NULL.
1069 All outstanding data was written correctly to the
1070 device if the Event is NULL.
1071 @retval EFI_DEVICE_ERROR The device reported an error while writting back
1073 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1074 @retval EFI_NO_MEDIA There is no media in the device.
1075 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1076 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
1082 PartitionFlushBlocksEx (
1083 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
1084 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
1088 PARTITION_PRIVATE_DATA
*Private
;
1089 PARTITION_ACCESS_TASK
*Task
;
1091 Private
= PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This
);
1093 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1094 Task
= PartitionCreateAccessTask (Token
);
1096 return EFI_OUT_OF_RESOURCES
;
1099 Status
= Private
->DiskIo2
->FlushDiskEx (Private
->DiskIo2
, &Task
->DiskIo2Token
);
1100 if (EFI_ERROR (Status
)) {
1101 gBS
->CloseEvent (Task
->DiskIo2Token
.Event
);
1105 Status
= Private
->DiskIo2
->FlushDiskEx (Private
->DiskIo2
, NULL
);
1112 Create a child handle for a logical block device that represents the
1113 bytes Start to End of the Parent Block IO device.
1115 @param[in] This Protocol instance pointer.
1116 @param[in] ParentHandle Parent Handle for new child.
1117 @param[in] ParentDiskIo Parent DiskIo interface.
1118 @param[in] ParentDiskIo2 Parent DiskIo2 interface.
1119 @param[in] ParentBlockIo Parent BlockIo interface.
1120 @param[in] ParentBlockIo2 Parent BlockIo2 interface.
1121 @param[in] ParentDevicePath Parent Device Path.
1122 @param[in] DevicePathNode Child Device Path node.
1123 @param[in] PartitionInfo Child Partition Information interface.
1124 @param[in] Start Start Block.
1125 @param[in] End End Block.
1126 @param[in] BlockSize Child block size.
1127 @param[in] TypeGuid Partition GUID Type.
1129 @retval EFI_SUCCESS A child handle was added.
1130 @retval other A child handle was not added.
1134 PartitionInstallChildHandle (
1135 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1136 IN EFI_HANDLE ParentHandle
,
1137 IN EFI_DISK_IO_PROTOCOL
*ParentDiskIo
,
1138 IN EFI_DISK_IO2_PROTOCOL
*ParentDiskIo2
,
1139 IN EFI_BLOCK_IO_PROTOCOL
*ParentBlockIo
,
1140 IN EFI_BLOCK_IO2_PROTOCOL
*ParentBlockIo2
,
1141 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
1142 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
,
1143 IN EFI_PARTITION_INFO_PROTOCOL
*PartitionInfo
,
1146 IN UINT32 BlockSize
,
1147 IN EFI_GUID
*TypeGuid
1151 PARTITION_PRIVATE_DATA
*Private
;
1153 Status
= EFI_SUCCESS
;
1154 Private
= AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA
));
1155 if (Private
== NULL
) {
1156 return EFI_OUT_OF_RESOURCES
;
1159 Private
->Signature
= PARTITION_PRIVATE_DATA_SIGNATURE
;
1161 Private
->Start
= MultU64x32 (Start
, ParentBlockIo
->Media
->BlockSize
);
1162 Private
->End
= MultU64x32 (End
+ 1, ParentBlockIo
->Media
->BlockSize
);
1164 Private
->BlockSize
= BlockSize
;
1165 Private
->ParentBlockIo
= ParentBlockIo
;
1166 Private
->ParentBlockIo2
= ParentBlockIo2
;
1167 Private
->DiskIo
= ParentDiskIo
;
1168 Private
->DiskIo2
= ParentDiskIo2
;
1171 // Set the BlockIO into Private Data.
1173 Private
->BlockIo
.Revision
= ParentBlockIo
->Revision
;
1175 Private
->BlockIo
.Media
= &Private
->Media
;
1176 CopyMem (Private
->BlockIo
.Media
, ParentBlockIo
->Media
, sizeof (EFI_BLOCK_IO_MEDIA
));
1178 Private
->BlockIo
.Reset
= PartitionReset
;
1179 Private
->BlockIo
.ReadBlocks
= PartitionReadBlocks
;
1180 Private
->BlockIo
.WriteBlocks
= PartitionWriteBlocks
;
1181 Private
->BlockIo
.FlushBlocks
= PartitionFlushBlocks
;
1184 // Set the BlockIO2 into Private Data.
1186 if (Private
->DiskIo2
!= NULL
) {
1187 ASSERT (Private
->ParentBlockIo2
!= NULL
);
1188 Private
->BlockIo2
.Media
= &Private
->Media2
;
1189 CopyMem (Private
->BlockIo2
.Media
, ParentBlockIo2
->Media
, sizeof (EFI_BLOCK_IO_MEDIA
));
1191 Private
->BlockIo2
.Reset
= PartitionResetEx
;
1192 Private
->BlockIo2
.ReadBlocksEx
= PartitionReadBlocksEx
;
1193 Private
->BlockIo2
.WriteBlocksEx
= PartitionWriteBlocksEx
;
1194 Private
->BlockIo2
.FlushBlocksEx
= PartitionFlushBlocksEx
;
1197 Private
->Media
.IoAlign
= 0;
1198 Private
->Media
.LogicalPartition
= TRUE
;
1199 Private
->Media
.LastBlock
= DivU64x32 (
1202 ParentBlockIo
->Media
->BlockSize
1207 Private
->Media
.BlockSize
= (UINT32
)BlockSize
;
1209 Private
->Media2
.IoAlign
= 0;
1210 Private
->Media2
.LogicalPartition
= TRUE
;
1211 Private
->Media2
.LastBlock
= Private
->Media
.LastBlock
;
1212 Private
->Media2
.BlockSize
= (UINT32
)BlockSize
;
1215 // Per UEFI Spec, LowestAlignedLba, LogicalBlocksPerPhysicalBlock and OptimalTransferLengthGranularity must be 0
1216 // for logical partitions.
1218 if (Private
->BlockIo
.Revision
>= EFI_BLOCK_IO_PROTOCOL_REVISION2
) {
1219 Private
->Media
.LowestAlignedLba
= 0;
1220 Private
->Media
.LogicalBlocksPerPhysicalBlock
= 0;
1221 Private
->Media2
.LowestAlignedLba
= 0;
1222 Private
->Media2
.LogicalBlocksPerPhysicalBlock
= 0;
1223 if (Private
->BlockIo
.Revision
>= EFI_BLOCK_IO_PROTOCOL_REVISION3
) {
1224 Private
->Media
.OptimalTransferLengthGranularity
= 0;
1225 Private
->Media2
.OptimalTransferLengthGranularity
= 0;
1229 Private
->DevicePath
= AppendDevicePathNode (ParentDevicePath
, DevicePathNode
);
1231 if (Private
->DevicePath
== NULL
) {
1233 return EFI_OUT_OF_RESOURCES
;
1237 // Set the PartitionInfo into Private Data.
1239 CopyMem (&Private
->PartitionInfo
, PartitionInfo
, sizeof (EFI_PARTITION_INFO_PROTOCOL
));
1241 if (TypeGuid
!= NULL
) {
1242 CopyGuid (&(Private
->TypeGuid
), TypeGuid
);
1244 ZeroMem ((VOID
*)&(Private
->TypeGuid
), sizeof (EFI_GUID
));
1248 // Create the new handle.
1250 Private
->Handle
= NULL
;
1251 if (Private
->DiskIo2
!= NULL
) {
1252 Status
= gBS
->InstallMultipleProtocolInterfaces (
1254 &gEfiDevicePathProtocolGuid
,
1255 Private
->DevicePath
,
1256 &gEfiBlockIoProtocolGuid
,
1258 &gEfiBlockIo2ProtocolGuid
,
1260 &gEfiPartitionInfoProtocolGuid
,
1261 &Private
->PartitionInfo
,
1267 Status
= gBS
->InstallMultipleProtocolInterfaces (
1269 &gEfiDevicePathProtocolGuid
,
1270 Private
->DevicePath
,
1271 &gEfiBlockIoProtocolGuid
,
1273 &gEfiPartitionInfoProtocolGuid
,
1274 &Private
->PartitionInfo
,
1281 if (!EFI_ERROR (Status
)) {
1283 // Open the Parent Handle for the child
1285 Status
= gBS
->OpenProtocol (
1287 &gEfiDiskIoProtocolGuid
,
1288 (VOID
**)&ParentDiskIo
,
1289 This
->DriverBindingHandle
,
1291 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1294 FreePool (Private
->DevicePath
);
1298 // if the Status == EFI_ALREADY_STARTED, it means the child handles
1299 // are already installed. So return EFI_SUCCESS to avoid do the next
1300 // partition type check.
1302 if (Status
== EFI_ALREADY_STARTED
) {
1303 Status
= EFI_SUCCESS
;
1311 The user Entry Point for module Partition. The user code starts with this function.
1313 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1314 @param[in] SystemTable A pointer to the EFI System Table.
1316 @retval EFI_SUCCESS The entry point is executed successfully.
1317 @retval other Some error occurs when executing this entry point.
1322 InitializePartition (
1323 IN EFI_HANDLE ImageHandle
,
1324 IN EFI_SYSTEM_TABLE
*SystemTable
1330 // Install driver model protocol(s).
1332 Status
= EfiLibInstallDriverBindingComponentName2 (
1335 &gPartitionDriverBinding
,
1337 &gPartitionComponentName
,
1338 &gPartitionComponentName2
1340 ASSERT_EFI_ERROR (Status
);
1346 Test to see if there is any child on ControllerHandle.
1348 @param[in] ControllerHandle Handle of device to test.
1350 @retval TRUE There are children on the ControllerHandle.
1351 @retval FALSE No child is on the ControllerHandle.
1356 IN EFI_HANDLE ControllerHandle
1359 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY
*OpenInfoBuffer
;
1364 Status
= gBS
->OpenProtocolInformation (
1366 &gEfiDiskIoProtocolGuid
,
1370 ASSERT_EFI_ERROR (Status
);
1372 for (Index
= 0; Index
< EntryCount
; Index
++) {
1373 if ((OpenInfoBuffer
[Index
].Attributes
& EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
) != 0) {
1378 FreePool (OpenInfoBuffer
);
1380 return (BOOLEAN
)(Index
< EntryCount
);