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 This program and the accompanying materials
10 are licensed and made available under the terms and conditions of the BSD License
11 which accompanies this distribution. The full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 #include "Partition.h"
23 // Partition Driver Global Variables.
25 EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding
= {
26 PartitionDriverBindingSupported
,
27 PartitionDriverBindingStart
,
28 PartitionDriverBindingStop
,
30 // Grub4Dos copies the BPB of the first partition to the MBR. If the
31 // DriverBindingStart() of the Fat driver gets run before that of Partition
32 // driver only the first partition can be recognized.
33 // Let the driver binding version of Partition driver be higher than that of
34 // Fat driver to make sure the DriverBindingStart() of the Partition driver
35 // gets run before that of Fat driver so that all the partitions can be recognized.
43 // Prioritized function list to detect partition table.
45 PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable
[] = {
46 PartitionInstallGptChildHandles
,
47 PartitionInstallMbrChildHandles
,
48 PartitionInstallUdfChildHandles
,
53 Test to see if this driver supports ControllerHandle. Any ControllerHandle
54 than contains a BlockIo and DiskIo protocol or a BlockIo2 protocol can be
57 @param[in] This Protocol instance pointer.
58 @param[in] ControllerHandle Handle of device to test.
59 @param[in] RemainingDevicePath Optional parameter use to pick a specific child
62 @retval EFI_SUCCESS This driver supports this device
63 @retval EFI_ALREADY_STARTED This driver is already running on this device
64 @retval other This driver does not support this device
69 PartitionDriverBindingSupported (
70 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
71 IN EFI_HANDLE ControllerHandle
,
72 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
76 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
77 EFI_DISK_IO_PROTOCOL
*DiskIo
;
81 // Check RemainingDevicePath validation
83 if (RemainingDevicePath
!= NULL
) {
85 // Check if RemainingDevicePath is the End of Device Path Node,
86 // if yes, go on checking other conditions
88 if (!IsDevicePathEnd (RemainingDevicePath
)) {
90 // If RemainingDevicePath isn't the End of Device Path Node,
91 // check its validation
93 Node
= (EFI_DEV_PATH
*) RemainingDevicePath
;
94 if (Node
->DevPath
.Type
!= MEDIA_DEVICE_PATH
||
95 Node
->DevPath
.SubType
!= MEDIA_HARDDRIVE_DP
||
96 DevicePathNodeLength (&Node
->DevPath
) != sizeof (HARDDRIVE_DEVICE_PATH
)) {
97 return EFI_UNSUPPORTED
;
103 // Open the IO Abstraction(s) needed to perform the supported test
105 Status
= gBS
->OpenProtocol (
107 &gEfiDiskIoProtocolGuid
,
109 This
->DriverBindingHandle
,
111 EFI_OPEN_PROTOCOL_BY_DRIVER
113 if (Status
== EFI_ALREADY_STARTED
) {
116 if (EFI_ERROR (Status
)) {
120 // Close the I/O Abstraction(s) used to perform the supported test
124 &gEfiDiskIoProtocolGuid
,
125 This
->DriverBindingHandle
,
130 // Open the EFI Device Path protocol needed to perform the supported test
132 Status
= gBS
->OpenProtocol (
134 &gEfiDevicePathProtocolGuid
,
135 (VOID
**) &ParentDevicePath
,
136 This
->DriverBindingHandle
,
138 EFI_OPEN_PROTOCOL_BY_DRIVER
140 if (Status
== EFI_ALREADY_STARTED
) {
144 if (EFI_ERROR (Status
)) {
149 // Close protocol, don't use device path protocol in the Support() function
153 &gEfiDevicePathProtocolGuid
,
154 This
->DriverBindingHandle
,
159 // Open the IO Abstraction(s) needed to perform the supported test
161 Status
= gBS
->OpenProtocol (
163 &gEfiBlockIoProtocolGuid
,
165 This
->DriverBindingHandle
,
167 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
174 Start this driver on ControllerHandle by opening a Block IO or a Block IO2
175 or both, and Disk IO protocol, reading Device Path, and creating a child
176 handle with a Disk IO and device path protocol.
178 @param[in] This Protocol instance pointer.
179 @param[in] ControllerHandle Handle of device to bind driver to
180 @param[in] RemainingDevicePath Optional parameter use to pick a specific child
183 @retval EFI_SUCCESS This driver is added to ControllerHandle
184 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
185 @retval other This driver does not support this device
190 PartitionDriverBindingStart (
191 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
192 IN EFI_HANDLE ControllerHandle
,
193 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
197 EFI_STATUS OpenStatus
;
198 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
199 EFI_BLOCK_IO2_PROTOCOL
*BlockIo2
;
200 EFI_DISK_IO_PROTOCOL
*DiskIo
;
201 EFI_DISK_IO2_PROTOCOL
*DiskIo2
;
202 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
203 PARTITION_DETECT_ROUTINE
*Routine
;
204 BOOLEAN MediaPresent
;
208 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
210 // Check RemainingDevicePath validation
212 if (RemainingDevicePath
!= NULL
) {
214 // Check if RemainingDevicePath is the End of Device Path Node,
215 // if yes, return EFI_SUCCESS
217 if (IsDevicePathEnd (RemainingDevicePath
)) {
218 Status
= EFI_SUCCESS
;
224 // Try to open BlockIO and BlockIO2. If BlockIO would be opened, continue,
225 // otherwise, return error.
227 Status
= gBS
->OpenProtocol (
229 &gEfiBlockIoProtocolGuid
,
231 This
->DriverBindingHandle
,
233 EFI_OPEN_PROTOCOL_GET_PROTOCOL
235 if (EFI_ERROR (Status
)) {
239 Status
= gBS
->OpenProtocol (
241 &gEfiBlockIo2ProtocolGuid
,
243 This
->DriverBindingHandle
,
245 EFI_OPEN_PROTOCOL_GET_PROTOCOL
247 if (EFI_ERROR (Status
)) {
252 // Get the Device Path Protocol on ControllerHandle's handle.
254 Status
= gBS
->OpenProtocol (
256 &gEfiDevicePathProtocolGuid
,
257 (VOID
**) &ParentDevicePath
,
258 This
->DriverBindingHandle
,
260 EFI_OPEN_PROTOCOL_BY_DRIVER
262 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
267 // Get the DiskIo and DiskIo2.
269 Status
= gBS
->OpenProtocol (
271 &gEfiDiskIoProtocolGuid
,
273 This
->DriverBindingHandle
,
275 EFI_OPEN_PROTOCOL_BY_DRIVER
277 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
280 &gEfiDevicePathProtocolGuid
,
281 This
->DriverBindingHandle
,
289 Status
= gBS
->OpenProtocol (
291 &gEfiDiskIo2ProtocolGuid
,
293 This
->DriverBindingHandle
,
295 EFI_OPEN_PROTOCOL_BY_DRIVER
297 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
302 // Try to read blocks when there's media or it is removable physical partition.
304 Status
= EFI_UNSUPPORTED
;
305 MediaPresent
= BlockIo
->Media
->MediaPresent
;
306 if (BlockIo
->Media
->MediaPresent
||
307 (BlockIo
->Media
->RemovableMedia
&& !BlockIo
->Media
->LogicalPartition
)) {
309 // Try for GPT, then legacy MBR partition types, and then UDF and El Torito.
310 // If the media supports a given partition type install child handles to
311 // represent the partitions described by the media.
313 Routine
= &mPartitionDetectRoutineTable
[0];
314 while (*Routine
!= NULL
) {
315 Status
= (*Routine
) (
324 if (!EFI_ERROR (Status
) || Status
== EFI_MEDIA_CHANGED
|| Status
== EFI_NO_MEDIA
) {
331 // In the case that the driver is already started (OpenStatus == EFI_ALREADY_STARTED),
332 // the DevicePathProtocol and the DiskIoProtocol are not actually opened by the
333 // driver. So don't try to close them. Otherwise, we will break the dependency
334 // between the controller and the driver set up before.
336 // In the case that when the media changes on a device it will Reinstall the
337 // BlockIo interaface. This will cause a call to our Stop(), and a subsequent
338 // reentrant call to our Start() successfully. We should leave the device open
339 // when this happen. The "media change" case includes either the status is
340 // EFI_MEDIA_CHANGED or it is a "media" to "no media" change.
342 if (EFI_ERROR (Status
) &&
343 !EFI_ERROR (OpenStatus
) &&
344 Status
!= EFI_MEDIA_CHANGED
&&
345 !(MediaPresent
&& Status
== EFI_NO_MEDIA
)) {
348 &gEfiDiskIoProtocolGuid
,
349 This
->DriverBindingHandle
,
353 // Close Parent DiskIo2 if has.
357 &gEfiDiskIo2ProtocolGuid
,
358 This
->DriverBindingHandle
,
364 &gEfiDevicePathProtocolGuid
,
365 This
->DriverBindingHandle
,
371 gBS
->RestoreTPL (OldTpl
);
376 Stop this driver on ControllerHandle. Support stopping any child handles
377 created by this driver.
379 @param This Protocol instance pointer.
380 @param ControllerHandle Handle of device to stop driver on
381 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
382 children is zero stop the entire bus driver.
383 @param ChildHandleBuffer List of Child Handles to Stop.
385 @retval EFI_SUCCESS This driver is removed ControllerHandle
386 @retval other This driver was not removed from this device
391 PartitionDriverBindingStop (
392 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
393 IN EFI_HANDLE ControllerHandle
,
394 IN UINTN NumberOfChildren
,
395 IN EFI_HANDLE
*ChildHandleBuffer
400 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
401 EFI_BLOCK_IO2_PROTOCOL
*BlockIo2
;
402 BOOLEAN AllChildrenStopped
;
403 PARTITION_PRIVATE_DATA
*Private
;
404 EFI_DISK_IO_PROTOCOL
*DiskIo
;
411 if (NumberOfChildren
== 0) {
413 // In the case of re-entry of the PartitionDriverBindingStop, the
414 // NumberOfChildren may not reflect the actual number of children on the
415 // bus driver. Hence, additional check is needed here.
417 if (HasChildren (ControllerHandle
)) {
418 DEBUG((EFI_D_ERROR
, "PartitionDriverBindingStop: Still has child.\n"));
419 return EFI_DEVICE_ERROR
;
423 // Close the bus driver
427 &gEfiDiskIoProtocolGuid
,
428 This
->DriverBindingHandle
,
432 // Close Parent BlockIO2 if has.
436 &gEfiDiskIo2ProtocolGuid
,
437 This
->DriverBindingHandle
,
443 &gEfiDevicePathProtocolGuid
,
444 This
->DriverBindingHandle
,
450 AllChildrenStopped
= TRUE
;
451 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
453 ChildHandleBuffer
[Index
],
454 &gEfiBlockIoProtocolGuid
,
456 This
->DriverBindingHandle
,
458 EFI_OPEN_PROTOCOL_GET_PROTOCOL
461 // Try to locate BlockIo2.
464 ChildHandleBuffer
[Index
],
465 &gEfiBlockIo2ProtocolGuid
,
467 This
->DriverBindingHandle
,
469 EFI_OPEN_PROTOCOL_GET_PROTOCOL
473 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo
);
474 if (Private
->InStop
) {
476 // If the child handle is going to be stopped again during the re-entry
477 // of DriverBindingStop, just do nothing.
481 Private
->InStop
= TRUE
;
483 BlockIo
->FlushBlocks (BlockIo
);
485 if (BlockIo2
!= NULL
) {
486 Status
= BlockIo2
->FlushBlocksEx (BlockIo2
, NULL
);
487 DEBUG((EFI_D_ERROR
, "PartitionDriverBindingStop: FlushBlocksEx returned with %r\n", Status
));
489 Status
= EFI_SUCCESS
;
494 &gEfiDiskIoProtocolGuid
,
495 This
->DriverBindingHandle
,
496 ChildHandleBuffer
[Index
]
499 if (IsZeroGuid (&Private
->TypeGuid
)) {
502 TypeGuid
= &Private
->TypeGuid
;
506 // All Software protocols have be freed from the handle so remove it.
507 // Remove the BlockIo Protocol if has.
508 // Remove the BlockIo2 Protocol if has.
510 if (BlockIo2
!= NULL
) {
512 // Some device drivers might re-install the BlockIO(2) protocols for a
513 // media change condition. Therefore, if the FlushBlocksEx returned with
514 // EFI_MEDIA_CHANGED, just let the BindingStop fail to avoid potential
515 // reference of already stopped child handle.
517 if (Status
!= EFI_MEDIA_CHANGED
) {
518 Status
= gBS
->UninstallMultipleProtocolInterfaces (
519 ChildHandleBuffer
[Index
],
520 &gEfiDevicePathProtocolGuid
,
522 &gEfiBlockIoProtocolGuid
,
524 &gEfiBlockIo2ProtocolGuid
,
526 &gEfiPartitionInfoProtocolGuid
,
527 &Private
->PartitionInfo
,
534 Status
= gBS
->UninstallMultipleProtocolInterfaces (
535 ChildHandleBuffer
[Index
],
536 &gEfiDevicePathProtocolGuid
,
538 &gEfiBlockIoProtocolGuid
,
540 &gEfiPartitionInfoProtocolGuid
,
541 &Private
->PartitionInfo
,
548 if (EFI_ERROR (Status
)) {
549 Private
->InStop
= FALSE
;
552 &gEfiDiskIoProtocolGuid
,
554 This
->DriverBindingHandle
,
555 ChildHandleBuffer
[Index
],
556 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
559 FreePool (Private
->DevicePath
);
563 if (EFI_ERROR (Status
)) {
564 AllChildrenStopped
= FALSE
;
565 if (Status
== EFI_MEDIA_CHANGED
) {
571 if (!AllChildrenStopped
) {
572 return EFI_DEVICE_ERROR
;
580 Reset the Block Device.
582 @param This Protocol instance pointer.
583 @param ExtendedVerification Driver may perform diagnostics on reset.
585 @retval EFI_SUCCESS The device was reset.
586 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
593 IN EFI_BLOCK_IO_PROTOCOL
*This
,
594 IN BOOLEAN ExtendedVerification
597 PARTITION_PRIVATE_DATA
*Private
;
599 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
601 return Private
->ParentBlockIo
->Reset (
602 Private
->ParentBlockIo
,
608 Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED
609 for no media or media change case. Otherwise DefaultStatus is returned.
611 @param DiskIo Pointer to the DiskIo instance.
612 @param MediaId Id of the media, changes every time the media is replaced.
613 @param DefaultStatus The default status to return when it's not the no media
614 or media change case.
616 @retval EFI_NO_MEDIA There is no media.
617 @retval EFI_MEDIA_CHANGED The media was changed.
618 @retval others The default status to return.
622 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
624 IN EFI_STATUS DefaultStatus
631 // Read 1 byte from offset 0 to check if the MediaId is still valid.
632 // The reading operation is synchronious thus it is not worth it to
633 // allocate a buffer from the pool. The destination buffer for the
634 // data is in the stack.
636 Status
= DiskIo
->ReadDisk (DiskIo
, MediaId
, 0, 1, (VOID
*)Buffer
);
637 if ((Status
== EFI_NO_MEDIA
) || (Status
== EFI_MEDIA_CHANGED
)) {
640 return DefaultStatus
;
644 Read by using the Disk IO protocol on the parent device. Lba addresses
645 must be converted to byte offsets.
647 @param This Protocol instance pointer.
648 @param MediaId Id of the media, changes every time the media is replaced.
649 @param Lba The starting Logical Block Address to read from
650 @param BufferSize Size of Buffer, must be a multiple of device block size.
651 @param Buffer Buffer containing read data
653 @retval EFI_SUCCESS The data was read correctly from the device.
654 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
655 @retval EFI_NO_MEDIA There is no media in the device.
656 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
657 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
658 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
659 valid for the device.
664 PartitionReadBlocks (
665 IN EFI_BLOCK_IO_PROTOCOL
*This
,
672 PARTITION_PRIVATE_DATA
*Private
;
675 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
677 if (BufferSize
% Private
->BlockSize
!= 0) {
678 return ProbeMediaStatus (Private
->DiskIo
, MediaId
, EFI_BAD_BUFFER_SIZE
);
681 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
682 if (Offset
+ BufferSize
> Private
->End
) {
683 return ProbeMediaStatus (Private
->DiskIo
, MediaId
, EFI_INVALID_PARAMETER
);
686 // Because some kinds of partition have different block size from their parent
687 // device, we call the Disk IO protocol on the parent device, not the Block IO
690 return Private
->DiskIo
->ReadDisk (Private
->DiskIo
, MediaId
, Offset
, BufferSize
, Buffer
);
694 Write by using the Disk IO protocol on the parent device. Lba addresses
695 must be converted to byte offsets.
697 @param[in] This Protocol instance pointer.
698 @param[in] MediaId Id of the media, changes every time the media is replaced.
699 @param[in] Lba The starting Logical Block Address to read from
700 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
701 @param[in] Buffer Buffer containing data to be written to device.
703 @retval EFI_SUCCESS The data was written correctly to the device.
704 @retval EFI_WRITE_PROTECTED The device can not be written to.
705 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
706 @retval EFI_NO_MEDIA There is no media in the device.
707 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
708 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
709 @retval EFI_INVALID_PARAMETER The write request contains a LBA that is not
710 valid for the device.
715 PartitionWriteBlocks (
716 IN EFI_BLOCK_IO_PROTOCOL
*This
,
723 PARTITION_PRIVATE_DATA
*Private
;
726 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
728 if (BufferSize
% Private
->BlockSize
!= 0) {
729 return ProbeMediaStatus (Private
->DiskIo
, MediaId
, EFI_BAD_BUFFER_SIZE
);
732 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
733 if (Offset
+ BufferSize
> Private
->End
) {
734 return ProbeMediaStatus (Private
->DiskIo
, MediaId
, EFI_INVALID_PARAMETER
);
737 // Because some kinds of partition have different block size from their parent
738 // device, we call the Disk IO protocol on the parent device, not the Block IO
741 return Private
->DiskIo
->WriteDisk (Private
->DiskIo
, MediaId
, Offset
, BufferSize
, Buffer
);
746 Flush the parent Block Device.
748 @param This Protocol instance pointer.
750 @retval EFI_SUCCESS All outstanding data was written to the device
751 @retval EFI_DEVICE_ERROR The device reported an error while writting back the data
752 @retval EFI_NO_MEDIA There is no media in the device.
757 PartitionFlushBlocks (
758 IN EFI_BLOCK_IO_PROTOCOL
*This
761 PARTITION_PRIVATE_DATA
*Private
;
763 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
765 return Private
->ParentBlockIo
->FlushBlocks (Private
->ParentBlockIo
);
769 Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED
770 for no media or media change case. Otherwise DefaultStatus is returned.
772 @param DiskIo2 Pointer to the DiskIo2 instance.
773 @param MediaId Id of the media, changes every time the media is replaced.
774 @param DefaultStatus The default status to return when it's not the no media
775 or media change case.
777 @retval EFI_NO_MEDIA There is no media.
778 @retval EFI_MEDIA_CHANGED The media was changed.
779 @retval others The default status to return.
783 IN EFI_DISK_IO2_PROTOCOL
*DiskIo2
,
785 IN EFI_STATUS DefaultStatus
792 // Read 1 byte from offset 0 to check if the MediaId is still valid.
793 // The reading operation is synchronious thus it is not worth it to
794 // allocate a buffer from the pool. The destination buffer for the
795 // data is in the stack.
797 Status
= DiskIo2
->ReadDiskEx (DiskIo2
, MediaId
, 0, NULL
, 1, (VOID
*)Buffer
);
798 if ((Status
== EFI_NO_MEDIA
) || (Status
== EFI_MEDIA_CHANGED
)) {
801 return DefaultStatus
;
805 Reset the Block Device throught Block I/O2 protocol.
807 @param This Protocol instance pointer.
808 @param ExtendedVerification Driver may perform diagnostics on reset.
810 @retval EFI_SUCCESS The device was reset.
811 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
818 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
819 IN BOOLEAN ExtendedVerification
822 PARTITION_PRIVATE_DATA
*Private
;
824 Private
= PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This
);
826 return Private
->ParentBlockIo2
->Reset (
827 Private
->ParentBlockIo2
,
833 The general callback for the DiskIo2 interfaces.
834 @param Event Event whose notification function is being invoked.
835 @param Context The pointer to the notification function's context,
836 which points to the PARTITION_ACCESS_TASK instance.
840 PartitionOnAccessComplete (
845 PARTITION_ACCESS_TASK
*Task
;
847 Task
= (PARTITION_ACCESS_TASK
*) Context
;
849 gBS
->CloseEvent (Event
);
851 Task
->BlockIo2Token
->TransactionStatus
= Task
->DiskIo2Token
.TransactionStatus
;
852 gBS
->SignalEvent (Task
->BlockIo2Token
->Event
);
858 Create a new PARTITION_ACCESS_TASK instance.
860 @param Token Pointer to the EFI_BLOCK_IO2_TOKEN.
862 @return Pointer to the created PARTITION_ACCESS_TASK instance or NULL upon failure.
864 PARTITION_ACCESS_TASK
*
865 PartitionCreateAccessTask (
866 IN EFI_BLOCK_IO2_TOKEN
*Token
870 PARTITION_ACCESS_TASK
*Task
;
872 Task
= AllocatePool (sizeof (*Task
));
877 Status
= gBS
->CreateEvent (
880 PartitionOnAccessComplete
,
882 &Task
->DiskIo2Token
.Event
884 if (EFI_ERROR (Status
)) {
889 Task
->BlockIo2Token
= Token
;
895 Read BufferSize bytes from Lba into Buffer.
897 This function reads the requested number of blocks from the device. All the
898 blocks are read, or an error is returned.
899 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and
900 non-blocking I/O is being used, the Event associated with this request will
903 @param[in] This Indicates a pointer to the calling context.
904 @param[in] MediaId Id of the media, changes every time the media is
906 @param[in] Lba The starting Logical Block Address to read from.
907 @param[in, out] Token A pointer to the token associated with the transaction.
908 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
909 @param[out] Buffer A pointer to the destination buffer for the data. The
910 caller is responsible for either having implicit or
911 explicit ownership of the buffer.
913 @retval EFI_SUCCESS The read request was queued if Token->Event is
914 not NULL.The data was read correctly from the
915 device if the Token->Event is NULL.
916 @retval EFI_DEVICE_ERROR The device reported an error while performing
918 @retval EFI_NO_MEDIA There is no media in the device.
919 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
920 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
921 intrinsic block size of the device.
922 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
923 or the buffer is not on proper alignment.
924 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
929 PartitionReadBlocksEx (
930 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
933 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
939 PARTITION_PRIVATE_DATA
*Private
;
941 PARTITION_ACCESS_TASK
*Task
;
943 Private
= PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This
);
945 if (BufferSize
% Private
->BlockSize
!= 0) {
946 return ProbeMediaStatusEx (Private
->DiskIo2
, MediaId
, EFI_BAD_BUFFER_SIZE
);
949 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
950 if (Offset
+ BufferSize
> Private
->End
) {
951 return ProbeMediaStatusEx (Private
->DiskIo2
, MediaId
, EFI_INVALID_PARAMETER
);
954 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
955 Task
= PartitionCreateAccessTask (Token
);
957 return EFI_OUT_OF_RESOURCES
;
960 Status
= Private
->DiskIo2
->ReadDiskEx (Private
->DiskIo2
, MediaId
, Offset
, &Task
->DiskIo2Token
, BufferSize
, Buffer
);
961 if (EFI_ERROR (Status
)) {
962 gBS
->CloseEvent (Task
->DiskIo2Token
.Event
);
966 Status
= Private
->DiskIo2
->ReadDiskEx (Private
->DiskIo2
, MediaId
, Offset
, NULL
, BufferSize
, Buffer
);
973 Write BufferSize bytes from Lba into Buffer.
975 This function writes the requested number of blocks to the device. All blocks
976 are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
977 EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
978 being used, the Event associated with this request will not be signaled.
980 @param[in] This Indicates a pointer to the calling context.
981 @param[in] MediaId The media ID that the write request is for.
982 @param[in] Lba The starting logical block address to be written. The
983 caller is responsible for writing to only legitimate
985 @param[in, out] Token A pointer to the token associated with the transaction.
986 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
987 @param[in] Buffer A pointer to the source buffer for the data.
989 @retval EFI_SUCCESS The write request was queued if Event is not NULL.
990 The data was written correctly to the device if
992 @retval EFI_WRITE_PROTECTED The device can not be written to.
993 @retval EFI_NO_MEDIA There is no media in the device.
994 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
995 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
996 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
997 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
998 or the buffer is not on proper alignment.
999 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
1005 PartitionWriteBlocksEx (
1006 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
1009 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
1010 IN UINTN BufferSize
,
1015 PARTITION_PRIVATE_DATA
*Private
;
1017 PARTITION_ACCESS_TASK
*Task
;
1019 Private
= PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This
);
1021 if (BufferSize
% Private
->BlockSize
!= 0) {
1022 return ProbeMediaStatusEx (Private
->DiskIo2
, MediaId
, EFI_BAD_BUFFER_SIZE
);
1025 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
1026 if (Offset
+ BufferSize
> Private
->End
) {
1027 return ProbeMediaStatusEx (Private
->DiskIo2
, MediaId
, EFI_INVALID_PARAMETER
);
1030 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1031 Task
= PartitionCreateAccessTask (Token
);
1033 return EFI_OUT_OF_RESOURCES
;
1036 Status
= Private
->DiskIo2
->WriteDiskEx (Private
->DiskIo2
, MediaId
, Offset
, &Task
->DiskIo2Token
, BufferSize
, Buffer
);
1037 if (EFI_ERROR (Status
)) {
1038 gBS
->CloseEvent (Task
->DiskIo2Token
.Event
);
1042 Status
= Private
->DiskIo2
->WriteDiskEx (Private
->DiskIo2
, MediaId
, Offset
, NULL
, BufferSize
, Buffer
);
1048 Flush the Block Device.
1050 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED
1051 is returned and non-blocking I/O is being used, the Event associated with
1052 this request will not be signaled.
1054 @param[in] This Indicates a pointer to the calling context.
1055 @param[in, out] Token A pointer to the token associated with the transaction
1057 @retval EFI_SUCCESS The flush request was queued if Event is not NULL.
1058 All outstanding data was written correctly to the
1059 device if the Event is NULL.
1060 @retval EFI_DEVICE_ERROR The device reported an error while writting back
1062 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1063 @retval EFI_NO_MEDIA There is no media in the device.
1064 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1065 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
1071 PartitionFlushBlocksEx (
1072 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
1073 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
1077 PARTITION_PRIVATE_DATA
*Private
;
1078 PARTITION_ACCESS_TASK
*Task
;
1080 Private
= PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This
);
1082 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1083 Task
= PartitionCreateAccessTask (Token
);
1085 return EFI_OUT_OF_RESOURCES
;
1088 Status
= Private
->DiskIo2
->FlushDiskEx (Private
->DiskIo2
, &Task
->DiskIo2Token
);
1089 if (EFI_ERROR (Status
)) {
1090 gBS
->CloseEvent (Task
->DiskIo2Token
.Event
);
1094 Status
= Private
->DiskIo2
->FlushDiskEx (Private
->DiskIo2
, NULL
);
1101 Create a child handle for a logical block device that represents the
1102 bytes Start to End of the Parent Block IO device.
1104 @param[in] This Protocol instance pointer.
1105 @param[in] ParentHandle Parent Handle for new child.
1106 @param[in] ParentDiskIo Parent DiskIo interface.
1107 @param[in] ParentDiskIo2 Parent DiskIo2 interface.
1108 @param[in] ParentBlockIo Parent BlockIo interface.
1109 @param[in] ParentBlockIo2 Parent BlockIo2 interface.
1110 @param[in] ParentDevicePath Parent Device Path.
1111 @param[in] DevicePathNode Child Device Path node.
1112 @param[in] PartitionInfo Child Partition Information interface.
1113 @param[in] Start Start Block.
1114 @param[in] End End Block.
1115 @param[in] BlockSize Child block size.
1116 @param[in] TypeGuid Partition GUID Type.
1118 @retval EFI_SUCCESS A child handle was added.
1119 @retval other A child handle was not added.
1123 PartitionInstallChildHandle (
1124 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1125 IN EFI_HANDLE ParentHandle
,
1126 IN EFI_DISK_IO_PROTOCOL
*ParentDiskIo
,
1127 IN EFI_DISK_IO2_PROTOCOL
*ParentDiskIo2
,
1128 IN EFI_BLOCK_IO_PROTOCOL
*ParentBlockIo
,
1129 IN EFI_BLOCK_IO2_PROTOCOL
*ParentBlockIo2
,
1130 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
1131 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
,
1132 IN EFI_PARTITION_INFO_PROTOCOL
*PartitionInfo
,
1135 IN UINT32 BlockSize
,
1136 IN EFI_GUID
*TypeGuid
1140 PARTITION_PRIVATE_DATA
*Private
;
1142 Status
= EFI_SUCCESS
;
1143 Private
= AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA
));
1144 if (Private
== NULL
) {
1145 return EFI_OUT_OF_RESOURCES
;
1148 Private
->Signature
= PARTITION_PRIVATE_DATA_SIGNATURE
;
1150 Private
->Start
= MultU64x32 (Start
, ParentBlockIo
->Media
->BlockSize
);
1151 Private
->End
= MultU64x32 (End
+ 1, ParentBlockIo
->Media
->BlockSize
);
1153 Private
->BlockSize
= BlockSize
;
1154 Private
->ParentBlockIo
= ParentBlockIo
;
1155 Private
->ParentBlockIo2
= ParentBlockIo2
;
1156 Private
->DiskIo
= ParentDiskIo
;
1157 Private
->DiskIo2
= ParentDiskIo2
;
1160 // Set the BlockIO into Private Data.
1162 Private
->BlockIo
.Revision
= ParentBlockIo
->Revision
;
1164 Private
->BlockIo
.Media
= &Private
->Media
;
1165 CopyMem (Private
->BlockIo
.Media
, ParentBlockIo
->Media
, sizeof (EFI_BLOCK_IO_MEDIA
));
1167 Private
->BlockIo
.Reset
= PartitionReset
;
1168 Private
->BlockIo
.ReadBlocks
= PartitionReadBlocks
;
1169 Private
->BlockIo
.WriteBlocks
= PartitionWriteBlocks
;
1170 Private
->BlockIo
.FlushBlocks
= PartitionFlushBlocks
;
1173 // Set the BlockIO2 into Private Data.
1175 if (Private
->DiskIo2
!= NULL
) {
1176 ASSERT (Private
->ParentBlockIo2
!= NULL
);
1177 Private
->BlockIo2
.Media
= &Private
->Media2
;
1178 CopyMem (Private
->BlockIo2
.Media
, ParentBlockIo2
->Media
, sizeof (EFI_BLOCK_IO_MEDIA
));
1180 Private
->BlockIo2
.Reset
= PartitionResetEx
;
1181 Private
->BlockIo2
.ReadBlocksEx
= PartitionReadBlocksEx
;
1182 Private
->BlockIo2
.WriteBlocksEx
= PartitionWriteBlocksEx
;
1183 Private
->BlockIo2
.FlushBlocksEx
= PartitionFlushBlocksEx
;
1186 Private
->Media
.IoAlign
= 0;
1187 Private
->Media
.LogicalPartition
= TRUE
;
1188 Private
->Media
.LastBlock
= DivU64x32 (
1191 ParentBlockIo
->Media
->BlockSize
1196 Private
->Media
.BlockSize
= (UINT32
) BlockSize
;
1198 Private
->Media2
.IoAlign
= 0;
1199 Private
->Media2
.LogicalPartition
= TRUE
;
1200 Private
->Media2
.LastBlock
= Private
->Media
.LastBlock
;
1201 Private
->Media2
.BlockSize
= (UINT32
) BlockSize
;
1204 // Per UEFI Spec, LowestAlignedLba, LogicalBlocksPerPhysicalBlock and OptimalTransferLengthGranularity must be 0
1205 // for logical partitions.
1207 if (Private
->BlockIo
.Revision
>= EFI_BLOCK_IO_PROTOCOL_REVISION2
) {
1208 Private
->Media
.LowestAlignedLba
= 0;
1209 Private
->Media
.LogicalBlocksPerPhysicalBlock
= 0;
1210 Private
->Media2
.LowestAlignedLba
= 0;
1211 Private
->Media2
.LogicalBlocksPerPhysicalBlock
= 0;
1212 if (Private
->BlockIo
.Revision
>= EFI_BLOCK_IO_PROTOCOL_REVISION3
) {
1213 Private
->Media
.OptimalTransferLengthGranularity
= 0;
1214 Private
->Media2
.OptimalTransferLengthGranularity
= 0;
1218 Private
->DevicePath
= AppendDevicePathNode (ParentDevicePath
, DevicePathNode
);
1220 if (Private
->DevicePath
== NULL
) {
1222 return EFI_OUT_OF_RESOURCES
;
1226 // Set the PartitionInfo into Private Data.
1228 CopyMem (&Private
->PartitionInfo
, PartitionInfo
, sizeof (EFI_PARTITION_INFO_PROTOCOL
));
1230 if (TypeGuid
!= NULL
) {
1231 CopyGuid(&(Private
->TypeGuid
), TypeGuid
);
1233 ZeroMem ((VOID
*)&(Private
->TypeGuid
), sizeof (EFI_GUID
));
1237 // Create the new handle.
1239 Private
->Handle
= NULL
;
1240 if (Private
->DiskIo2
!= NULL
) {
1241 Status
= gBS
->InstallMultipleProtocolInterfaces (
1243 &gEfiDevicePathProtocolGuid
,
1244 Private
->DevicePath
,
1245 &gEfiBlockIoProtocolGuid
,
1247 &gEfiBlockIo2ProtocolGuid
,
1249 &gEfiPartitionInfoProtocolGuid
,
1250 &Private
->PartitionInfo
,
1256 Status
= gBS
->InstallMultipleProtocolInterfaces (
1258 &gEfiDevicePathProtocolGuid
,
1259 Private
->DevicePath
,
1260 &gEfiBlockIoProtocolGuid
,
1262 &gEfiPartitionInfoProtocolGuid
,
1263 &Private
->PartitionInfo
,
1270 if (!EFI_ERROR (Status
)) {
1272 // Open the Parent Handle for the child
1274 Status
= gBS
->OpenProtocol (
1276 &gEfiDiskIoProtocolGuid
,
1277 (VOID
**) &ParentDiskIo
,
1278 This
->DriverBindingHandle
,
1280 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1283 FreePool (Private
->DevicePath
);
1292 The user Entry Point for module Partition. The user code starts with this function.
1294 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1295 @param[in] SystemTable A pointer to the EFI System Table.
1297 @retval EFI_SUCCESS The entry point is executed successfully.
1298 @retval other Some error occurs when executing this entry point.
1303 InitializePartition (
1304 IN EFI_HANDLE ImageHandle
,
1305 IN EFI_SYSTEM_TABLE
*SystemTable
1311 // Install driver model protocol(s).
1313 Status
= EfiLibInstallDriverBindingComponentName2 (
1316 &gPartitionDriverBinding
,
1318 &gPartitionComponentName
,
1319 &gPartitionComponentName2
1321 ASSERT_EFI_ERROR (Status
);
1329 Test to see if there is any child on ControllerHandle.
1331 @param[in] ControllerHandle Handle of device to test.
1333 @retval TRUE There are children on the ControllerHandle.
1334 @retval FALSE No child is on the ControllerHandle.
1339 IN EFI_HANDLE ControllerHandle
1342 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY
*OpenInfoBuffer
;
1347 Status
= gBS
->OpenProtocolInformation (
1349 &gEfiDiskIoProtocolGuid
,
1353 ASSERT_EFI_ERROR (Status
);
1355 for (Index
= 0; Index
< EntryCount
; Index
++) {
1356 if ((OpenInfoBuffer
[Index
].Attributes
& EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
) != 0) {
1360 FreePool (OpenInfoBuffer
);
1362 return (BOOLEAN
) (Index
< EntryCount
);