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 - 2014, Intel Corporation. All rights reserved.<BR>
8 This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
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
173 Start this driver on ControllerHandle by opening a Block IO or a Block IO2
174 or both, and Disk IO protocol, reading Device Path, and creating a child
175 handle with a Disk IO and device path protocol.
177 @param[in] This Protocol instance pointer.
178 @param[in] ControllerHandle Handle of device to bind driver to
179 @param[in] RemainingDevicePath Optional parameter use to pick a specific child
182 @retval EFI_SUCCESS This driver is added to ControllerHandle
183 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
184 @retval other This driver does not support this device
189 PartitionDriverBindingStart (
190 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
191 IN EFI_HANDLE ControllerHandle
,
192 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
196 EFI_STATUS OpenStatus
;
197 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
198 EFI_BLOCK_IO2_PROTOCOL
*BlockIo2
;
199 EFI_DISK_IO_PROTOCOL
*DiskIo
;
200 EFI_DISK_IO2_PROTOCOL
*DiskIo2
;
201 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
202 PARTITION_DETECT_ROUTINE
*Routine
;
203 BOOLEAN MediaPresent
;
207 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
209 // Check RemainingDevicePath validation
211 if (RemainingDevicePath
!= NULL
) {
213 // Check if RemainingDevicePath is the End of Device Path Node,
214 // if yes, return EFI_SUCCESS
216 if (IsDevicePathEnd (RemainingDevicePath
)) {
217 Status
= EFI_SUCCESS
;
223 // Try to open BlockIO and BlockIO2. If BlockIO would be opened, continue,
224 // otherwise, return error.
226 Status
= gBS
->OpenProtocol (
228 &gEfiBlockIoProtocolGuid
,
230 This
->DriverBindingHandle
,
232 EFI_OPEN_PROTOCOL_GET_PROTOCOL
234 if (EFI_ERROR (Status
)) {
238 Status
= gBS
->OpenProtocol (
240 &gEfiBlockIo2ProtocolGuid
,
242 This
->DriverBindingHandle
,
244 EFI_OPEN_PROTOCOL_GET_PROTOCOL
246 if (EFI_ERROR (Status
)) {
251 // Get the Device Path Protocol on ControllerHandle's handle.
253 Status
= gBS
->OpenProtocol (
255 &gEfiDevicePathProtocolGuid
,
256 (VOID
**) &ParentDevicePath
,
257 This
->DriverBindingHandle
,
259 EFI_OPEN_PROTOCOL_BY_DRIVER
261 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
266 // Get the DiskIo and DiskIo2.
268 Status
= gBS
->OpenProtocol (
270 &gEfiDiskIoProtocolGuid
,
272 This
->DriverBindingHandle
,
274 EFI_OPEN_PROTOCOL_BY_DRIVER
276 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
279 &gEfiDevicePathProtocolGuid
,
280 This
->DriverBindingHandle
,
288 Status
= gBS
->OpenProtocol (
290 &gEfiDiskIo2ProtocolGuid
,
292 This
->DriverBindingHandle
,
294 EFI_OPEN_PROTOCOL_BY_DRIVER
296 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
301 // Try to read blocks when there's media or it is removable physical partition.
303 Status
= EFI_UNSUPPORTED
;
304 MediaPresent
= BlockIo
->Media
->MediaPresent
;
305 if (BlockIo
->Media
->MediaPresent
||
306 (BlockIo
->Media
->RemovableMedia
&& !BlockIo
->Media
->LogicalPartition
)) {
308 // Try for GPT, then El Torito, and then legacy MBR partition types. If the
309 // media supports a given partition type install child handles to represent
310 // the partitions described by the media.
312 Routine
= &mPartitionDetectRoutineTable
[0];
313 while (*Routine
!= NULL
) {
314 Status
= (*Routine
) (
323 if (!EFI_ERROR (Status
) || Status
== EFI_MEDIA_CHANGED
|| Status
== EFI_NO_MEDIA
) {
330 // In the case that the driver is already started (OpenStatus == EFI_ALREADY_STARTED),
331 // the DevicePathProtocol and the DiskIoProtocol are not actually opened by the
332 // driver. So don't try to close them. Otherwise, we will break the dependency
333 // between the controller and the driver set up before.
335 // In the case that when the media changes on a device it will Reinstall the
336 // BlockIo interaface. This will cause a call to our Stop(), and a subsequent
337 // reentrant call to our Start() successfully. We should leave the device open
338 // when this happen. The "media change" case includes either the status is
339 // EFI_MEDIA_CHANGED or it is a "media" to "no media" change.
341 if (EFI_ERROR (Status
) &&
342 !EFI_ERROR (OpenStatus
) &&
343 Status
!= EFI_MEDIA_CHANGED
&&
344 !(MediaPresent
&& Status
== EFI_NO_MEDIA
)) {
347 &gEfiDiskIoProtocolGuid
,
348 This
->DriverBindingHandle
,
352 // Close Parent DiskIo2 if has.
356 &gEfiDiskIo2ProtocolGuid
,
357 This
->DriverBindingHandle
,
363 &gEfiDevicePathProtocolGuid
,
364 This
->DriverBindingHandle
,
370 gBS
->RestoreTPL (OldTpl
);
375 Stop this driver on ControllerHandle. Support stopping any child handles
376 created by this driver.
378 @param This Protocol instance pointer.
379 @param ControllerHandle Handle of device to stop driver on
380 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
381 children is zero stop the entire bus driver.
382 @param ChildHandleBuffer List of Child Handles to Stop.
384 @retval EFI_SUCCESS This driver is removed ControllerHandle
385 @retval other This driver was not removed from this device
390 PartitionDriverBindingStop (
391 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
392 IN EFI_HANDLE ControllerHandle
,
393 IN UINTN NumberOfChildren
,
394 IN EFI_HANDLE
*ChildHandleBuffer
399 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
400 EFI_BLOCK_IO2_PROTOCOL
*BlockIo2
;
401 BOOLEAN AllChildrenStopped
;
402 PARTITION_PRIVATE_DATA
*Private
;
403 EFI_DISK_IO_PROTOCOL
*DiskIo
;
409 if (NumberOfChildren
== 0) {
411 // Close the bus driver
415 &gEfiDiskIoProtocolGuid
,
416 This
->DriverBindingHandle
,
420 // Close Parent BlockIO2 if has.
424 &gEfiDiskIo2ProtocolGuid
,
425 This
->DriverBindingHandle
,
431 &gEfiDevicePathProtocolGuid
,
432 This
->DriverBindingHandle
,
438 AllChildrenStopped
= TRUE
;
439 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
441 ChildHandleBuffer
[Index
],
442 &gEfiBlockIoProtocolGuid
,
444 This
->DriverBindingHandle
,
446 EFI_OPEN_PROTOCOL_GET_PROTOCOL
449 // Try to locate BlockIo2.
452 ChildHandleBuffer
[Index
],
453 &gEfiBlockIo2ProtocolGuid
,
455 This
->DriverBindingHandle
,
457 EFI_OPEN_PROTOCOL_GET_PROTOCOL
461 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo
);
463 Status
= gBS
->CloseProtocol (
465 &gEfiDiskIoProtocolGuid
,
466 This
->DriverBindingHandle
,
467 ChildHandleBuffer
[Index
]
470 // All Software protocols have be freed from the handle so remove it.
471 // Remove the BlockIo Protocol if has.
472 // Remove the BlockIo2 Protocol if has.
474 if (BlockIo2
!= NULL
) {
475 BlockIo
->FlushBlocks (BlockIo
);
476 BlockIo2
->FlushBlocksEx (BlockIo2
, NULL
);
477 Status
= gBS
->UninstallMultipleProtocolInterfaces (
478 ChildHandleBuffer
[Index
],
479 &gEfiDevicePathProtocolGuid
,
481 &gEfiBlockIoProtocolGuid
,
483 &gEfiBlockIo2ProtocolGuid
,
490 BlockIo
->FlushBlocks (BlockIo
);
491 Status
= gBS
->UninstallMultipleProtocolInterfaces (
492 ChildHandleBuffer
[Index
],
493 &gEfiDevicePathProtocolGuid
,
495 &gEfiBlockIoProtocolGuid
,
503 if (EFI_ERROR (Status
)) {
506 &gEfiDiskIoProtocolGuid
,
508 This
->DriverBindingHandle
,
509 ChildHandleBuffer
[Index
],
510 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
513 FreePool (Private
->DevicePath
);
517 if (EFI_ERROR (Status
)) {
518 AllChildrenStopped
= FALSE
;
522 if (!AllChildrenStopped
) {
523 return EFI_DEVICE_ERROR
;
531 Reset the Block Device.
533 @param This Protocol instance pointer.
534 @param ExtendedVerification Driver may perform diagnostics on reset.
536 @retval EFI_SUCCESS The device was reset.
537 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
544 IN EFI_BLOCK_IO_PROTOCOL
*This
,
545 IN BOOLEAN ExtendedVerification
548 PARTITION_PRIVATE_DATA
*Private
;
550 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
552 return Private
->ParentBlockIo
->Reset (
553 Private
->ParentBlockIo
,
559 Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED
560 for no media or media change case. Otherwise DefaultStatus is returned.
562 @param DiskIo Pointer to the DiskIo instance.
563 @param MediaId Id of the media, changes every time the media is replaced.
564 @param DefaultStatus The default status to return when it's not the no media
565 or media change case.
567 @retval EFI_NO_MEDIA There is no media.
568 @retval EFI_MEDIA_CHANGED The media was changed.
569 @retval others The default status to return.
573 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
575 IN EFI_STATUS DefaultStatus
582 // Read 1 byte from offset 0 to check if the MediaId is still valid.
583 // The reading operation is synchronious thus it is not worth it to
584 // allocate a buffer from the pool. The destination buffer for the
585 // data is in the stack.
587 Status
= DiskIo
->ReadDisk (DiskIo
, MediaId
, 0, 1, (VOID
*)Buffer
);
588 if ((Status
== EFI_NO_MEDIA
) || (Status
== EFI_MEDIA_CHANGED
)) {
591 return DefaultStatus
;
595 Read by using the Disk IO protocol on the parent device. Lba addresses
596 must be converted to byte offsets.
598 @param This Protocol instance pointer.
599 @param MediaId Id of the media, changes every time the media is replaced.
600 @param Lba The starting Logical Block Address to read from
601 @param BufferSize Size of Buffer, must be a multiple of device block size.
602 @param Buffer Buffer containing read data
604 @retval EFI_SUCCESS The data was read correctly from the device.
605 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
606 @retval EFI_NO_MEDIA There is no media in the device.
607 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
608 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
609 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
610 valid for the device.
615 PartitionReadBlocks (
616 IN EFI_BLOCK_IO_PROTOCOL
*This
,
623 PARTITION_PRIVATE_DATA
*Private
;
626 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
628 if (BufferSize
% Private
->BlockSize
!= 0) {
629 return ProbeMediaStatus (Private
->DiskIo
, MediaId
, EFI_BAD_BUFFER_SIZE
);
632 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
633 if (Offset
+ BufferSize
> Private
->End
) {
634 return ProbeMediaStatus (Private
->DiskIo
, MediaId
, EFI_INVALID_PARAMETER
);
637 // Because some kinds of partition have different block size from their parent
638 // device, we call the Disk IO protocol on the parent device, not the Block IO
641 return Private
->DiskIo
->ReadDisk (Private
->DiskIo
, MediaId
, Offset
, BufferSize
, Buffer
);
645 Write by using the Disk IO protocol on the parent device. Lba addresses
646 must be converted to byte offsets.
648 @param[in] This Protocol instance pointer.
649 @param[in] MediaId Id of the media, changes every time the media is replaced.
650 @param[in] Lba The starting Logical Block Address to read from
651 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
652 @param[in] Buffer Buffer containing data to be written to device.
654 @retval EFI_SUCCESS The data was written correctly to the device.
655 @retval EFI_WRITE_PROTECTED The device can not be written to.
656 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
657 @retval EFI_NO_MEDIA There is no media in the device.
658 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
659 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
660 @retval EFI_INVALID_PARAMETER The write request contains a LBA that is not
661 valid for the device.
666 PartitionWriteBlocks (
667 IN EFI_BLOCK_IO_PROTOCOL
*This
,
674 PARTITION_PRIVATE_DATA
*Private
;
677 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
679 if (BufferSize
% Private
->BlockSize
!= 0) {
680 return ProbeMediaStatus (Private
->DiskIo
, MediaId
, EFI_BAD_BUFFER_SIZE
);
683 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
684 if (Offset
+ BufferSize
> Private
->End
) {
685 return ProbeMediaStatus (Private
->DiskIo
, MediaId
, EFI_INVALID_PARAMETER
);
688 // Because some kinds of partition have different block size from their parent
689 // device, we call the Disk IO protocol on the parent device, not the Block IO
692 return Private
->DiskIo
->WriteDisk (Private
->DiskIo
, MediaId
, Offset
, BufferSize
, Buffer
);
697 Flush the parent Block Device.
699 @param This Protocol instance pointer.
701 @retval EFI_SUCCESS All outstanding data was written to the device
702 @retval EFI_DEVICE_ERROR The device reported an error while writting back the data
703 @retval EFI_NO_MEDIA There is no media in the device.
708 PartitionFlushBlocks (
709 IN EFI_BLOCK_IO_PROTOCOL
*This
712 PARTITION_PRIVATE_DATA
*Private
;
714 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
716 return Private
->ParentBlockIo
->FlushBlocks (Private
->ParentBlockIo
);
720 Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED
721 for no media or media change case. Otherwise DefaultStatus is returned.
723 @param DiskIo2 Pointer to the DiskIo2 instance.
724 @param MediaId Id of the media, changes every time the media is replaced.
725 @param DefaultStatus The default status to return when it's not the no media
726 or media change case.
728 @retval EFI_NO_MEDIA There is no media.
729 @retval EFI_MEDIA_CHANGED The media was changed.
730 @retval others The default status to return.
734 IN EFI_DISK_IO2_PROTOCOL
*DiskIo2
,
736 IN EFI_STATUS DefaultStatus
742 // Read 1 byte from offset 0 but passing NULL as buffer pointer
744 Status
= DiskIo2
->ReadDiskEx (DiskIo2
, MediaId
, 0, NULL
, 1, NULL
);
745 if ((Status
== EFI_NO_MEDIA
) || (Status
== EFI_MEDIA_CHANGED
)) {
748 return DefaultStatus
;
752 Reset the Block Device throught Block I/O2 protocol.
754 @param This Protocol instance pointer.
755 @param ExtendedVerification Driver may perform diagnostics on reset.
757 @retval EFI_SUCCESS The device was reset.
758 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
765 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
766 IN BOOLEAN ExtendedVerification
769 PARTITION_PRIVATE_DATA
*Private
;
771 Private
= PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This
);
773 return Private
->ParentBlockIo2
->Reset (
774 Private
->ParentBlockIo2
,
780 The general callback for the DiskIo2 interfaces.
781 @param Event Event whose notification function is being invoked.
782 @param Context The pointer to the notification function's context,
783 which points to the PARTITION_ACCESS_TASK instance.
787 PartitionOnAccessComplete (
792 PARTITION_ACCESS_TASK
*Task
;
794 Task
= (PARTITION_ACCESS_TASK
*) Context
;
796 gBS
->CloseEvent (Event
);
798 Task
->BlockIo2Token
->TransactionStatus
= Task
->DiskIo2Token
.TransactionStatus
;
799 gBS
->SignalEvent (Task
->BlockIo2Token
->Event
);
805 Create a new PARTITION_ACCESS_TASK instance.
807 @param Token Pointer to the EFI_BLOCK_IO2_TOKEN.
809 @return Pointer to the created PARTITION_ACCESS_TASK instance or NULL upon failure.
811 PARTITION_ACCESS_TASK
*
812 PartitionCreateAccessTask (
813 IN EFI_BLOCK_IO2_TOKEN
*Token
817 PARTITION_ACCESS_TASK
*Task
;
819 Task
= AllocatePool (sizeof (*Task
));
824 Status
= gBS
->CreateEvent (
827 PartitionOnAccessComplete
,
829 &Task
->DiskIo2Token
.Event
831 if (EFI_ERROR (Status
)) {
836 Task
->BlockIo2Token
= Token
;
842 Read BufferSize bytes from Lba into Buffer.
844 This function reads the requested number of blocks from the device. All the
845 blocks are read, or an error is returned.
846 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and
847 non-blocking I/O is being used, the Event associated with this request will
850 @param[in] This Indicates a pointer to the calling context.
851 @param[in] MediaId Id of the media, changes every time the media is
853 @param[in] Lba The starting Logical Block Address to read from.
854 @param[in, out] Token A pointer to the token associated with the transaction.
855 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
856 @param[out] Buffer A pointer to the destination buffer for the data. The
857 caller is responsible for either having implicit or
858 explicit ownership of the buffer.
860 @retval EFI_SUCCESS The read request was queued if Token->Event is
861 not NULL.The data was read correctly from the
862 device if the Token->Event is NULL.
863 @retval EFI_DEVICE_ERROR The device reported an error while performing
865 @retval EFI_NO_MEDIA There is no media in the device.
866 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
867 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
868 intrinsic block size of the device.
869 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
870 or the buffer is not on proper alignment.
871 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
876 PartitionReadBlocksEx (
877 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
880 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
886 PARTITION_PRIVATE_DATA
*Private
;
888 PARTITION_ACCESS_TASK
*Task
;
890 Private
= PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This
);
892 if (BufferSize
% Private
->BlockSize
!= 0) {
893 return ProbeMediaStatusEx (Private
->DiskIo2
, MediaId
, EFI_BAD_BUFFER_SIZE
);
896 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
897 if (Offset
+ BufferSize
> Private
->End
) {
898 return ProbeMediaStatusEx (Private
->DiskIo2
, MediaId
, EFI_INVALID_PARAMETER
);
901 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
902 Task
= PartitionCreateAccessTask (Token
);
904 return EFI_OUT_OF_RESOURCES
;
907 Status
= Private
->DiskIo2
->ReadDiskEx (Private
->DiskIo2
, MediaId
, Offset
, &Task
->DiskIo2Token
, BufferSize
, Buffer
);
908 if (EFI_ERROR (Status
)) {
909 gBS
->CloseEvent (Task
->DiskIo2Token
.Event
);
913 Status
= Private
->DiskIo2
->ReadDiskEx (Private
->DiskIo2
, MediaId
, Offset
, NULL
, BufferSize
, Buffer
);
920 Write BufferSize bytes from Lba into Buffer.
922 This function writes the requested number of blocks to the device. All blocks
923 are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
924 EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
925 being used, the Event associated with this request will not be signaled.
927 @param[in] This Indicates a pointer to the calling context.
928 @param[in] MediaId The media ID that the write request is for.
929 @param[in] Lba The starting logical block address to be written. The
930 caller is responsible for writing to only legitimate
932 @param[in, out] Token A pointer to the token associated with the transaction.
933 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
934 @param[in] Buffer A pointer to the source buffer for the data.
936 @retval EFI_SUCCESS The write request was queued if Event is not NULL.
937 The data was written correctly to the device if
939 @retval EFI_WRITE_PROTECTED The device can not be written to.
940 @retval EFI_NO_MEDIA There is no media in the device.
941 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
942 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
943 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
944 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
945 or the buffer is not on proper alignment.
946 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
952 PartitionWriteBlocksEx (
953 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
956 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
962 PARTITION_PRIVATE_DATA
*Private
;
964 PARTITION_ACCESS_TASK
*Task
;
966 Private
= PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This
);
968 if (BufferSize
% Private
->BlockSize
!= 0) {
969 return ProbeMediaStatusEx (Private
->DiskIo2
, MediaId
, EFI_BAD_BUFFER_SIZE
);
972 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
973 if (Offset
+ BufferSize
> Private
->End
) {
974 return ProbeMediaStatusEx (Private
->DiskIo2
, MediaId
, EFI_INVALID_PARAMETER
);
977 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
978 Task
= PartitionCreateAccessTask (Token
);
980 return EFI_OUT_OF_RESOURCES
;
983 Status
= Private
->DiskIo2
->WriteDiskEx (Private
->DiskIo2
, MediaId
, Offset
, &Task
->DiskIo2Token
, BufferSize
, Buffer
);
984 if (EFI_ERROR (Status
)) {
985 gBS
->CloseEvent (Task
->DiskIo2Token
.Event
);
989 Status
= Private
->DiskIo2
->WriteDiskEx (Private
->DiskIo2
, MediaId
, Offset
, NULL
, BufferSize
, Buffer
);
995 Flush the Block Device.
997 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED
998 is returned and non-blocking I/O is being used, the Event associated with
999 this request will not be signaled.
1001 @param[in] This Indicates a pointer to the calling context.
1002 @param[in, out] Token A pointer to the token associated with the transaction
1004 @retval EFI_SUCCESS The flush request was queued if Event is not NULL.
1005 All outstanding data was written correctly to the
1006 device if the Event is NULL.
1007 @retval EFI_DEVICE_ERROR The device reported an error while writting back
1009 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1010 @retval EFI_NO_MEDIA There is no media in the device.
1011 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1012 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
1018 PartitionFlushBlocksEx (
1019 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
1020 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
1024 PARTITION_PRIVATE_DATA
*Private
;
1025 PARTITION_ACCESS_TASK
*Task
;
1027 Private
= PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This
);
1029 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1030 Task
= PartitionCreateAccessTask (Token
);
1032 return EFI_OUT_OF_RESOURCES
;
1035 Status
= Private
->DiskIo2
->FlushDiskEx (Private
->DiskIo2
, &Task
->DiskIo2Token
);
1036 if (EFI_ERROR (Status
)) {
1037 gBS
->CloseEvent (Task
->DiskIo2Token
.Event
);
1041 Status
= Private
->DiskIo2
->FlushDiskEx (Private
->DiskIo2
, NULL
);
1048 Create a child handle for a logical block device that represents the
1049 bytes Start to End of the Parent Block IO device.
1051 @param[in] This Protocol instance pointer.
1052 @param[in] ParentHandle Parent Handle for new child.
1053 @param[in] ParentDiskIo Parent DiskIo interface.
1054 @param[in] ParentDiskIo2 Parent DiskIo2 interface.
1055 @param[in] ParentBlockIo Parent BlockIo interface.
1056 @param[in] ParentBlockIo2 Parent BlockIo2 interface.
1057 @param[in] ParentDevicePath Parent Device Path.
1058 @param[in] DevicePathNode Child Device Path node.
1059 @param[in] Start Start Block.
1060 @param[in] End End Block.
1061 @param[in] BlockSize Child block size.
1062 @param[in] InstallEspGuid Flag to install EFI System Partition GUID on handle.
1064 @retval EFI_SUCCESS A child handle was added.
1065 @retval other A child handle was not added.
1069 PartitionInstallChildHandle (
1070 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1071 IN EFI_HANDLE ParentHandle
,
1072 IN EFI_DISK_IO_PROTOCOL
*ParentDiskIo
,
1073 IN EFI_DISK_IO2_PROTOCOL
*ParentDiskIo2
,
1074 IN EFI_BLOCK_IO_PROTOCOL
*ParentBlockIo
,
1075 IN EFI_BLOCK_IO2_PROTOCOL
*ParentBlockIo2
,
1076 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
1077 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
,
1080 IN UINT32 BlockSize
,
1081 IN BOOLEAN InstallEspGuid
1085 PARTITION_PRIVATE_DATA
*Private
;
1087 Status
= EFI_SUCCESS
;
1088 Private
= AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA
));
1089 if (Private
== NULL
) {
1090 return EFI_OUT_OF_RESOURCES
;
1093 Private
->Signature
= PARTITION_PRIVATE_DATA_SIGNATURE
;
1095 Private
->Start
= MultU64x32 (Start
, ParentBlockIo
->Media
->BlockSize
);
1096 Private
->End
= MultU64x32 (End
+ 1, ParentBlockIo
->Media
->BlockSize
);
1098 Private
->BlockSize
= BlockSize
;
1099 Private
->ParentBlockIo
= ParentBlockIo
;
1100 Private
->ParentBlockIo2
= ParentBlockIo2
;
1101 Private
->DiskIo
= ParentDiskIo
;
1102 Private
->DiskIo2
= ParentDiskIo2
;
1105 // Set the BlockIO into Private Data.
1107 Private
->BlockIo
.Revision
= ParentBlockIo
->Revision
;
1109 Private
->BlockIo
.Media
= &Private
->Media
;
1110 CopyMem (Private
->BlockIo
.Media
, ParentBlockIo
->Media
, sizeof (EFI_BLOCK_IO_MEDIA
));
1112 Private
->BlockIo
.Reset
= PartitionReset
;
1113 Private
->BlockIo
.ReadBlocks
= PartitionReadBlocks
;
1114 Private
->BlockIo
.WriteBlocks
= PartitionWriteBlocks
;
1115 Private
->BlockIo
.FlushBlocks
= PartitionFlushBlocks
;
1118 // Set the BlockIO2 into Private Data.
1120 if (Private
->DiskIo2
!= NULL
) {
1121 ASSERT (Private
->ParentBlockIo2
!= NULL
);
1122 Private
->BlockIo2
.Media
= &Private
->Media2
;
1123 CopyMem (Private
->BlockIo2
.Media
, ParentBlockIo2
->Media
, sizeof (EFI_BLOCK_IO_MEDIA
));
1125 Private
->BlockIo2
.Reset
= PartitionResetEx
;
1126 Private
->BlockIo2
.ReadBlocksEx
= PartitionReadBlocksEx
;
1127 Private
->BlockIo2
.WriteBlocksEx
= PartitionWriteBlocksEx
;
1128 Private
->BlockIo2
.FlushBlocksEx
= PartitionFlushBlocksEx
;
1131 Private
->Media
.IoAlign
= 0;
1132 Private
->Media
.LogicalPartition
= TRUE
;
1133 Private
->Media
.LastBlock
= DivU64x32 (
1136 ParentBlockIo
->Media
->BlockSize
1141 Private
->Media
.BlockSize
= (UINT32
) BlockSize
;
1143 Private
->Media2
.IoAlign
= 0;
1144 Private
->Media2
.LogicalPartition
= TRUE
;
1145 Private
->Media2
.LastBlock
= Private
->Media
.LastBlock
;
1146 Private
->Media2
.BlockSize
= (UINT32
) BlockSize
;
1149 // Per UEFI Spec, LowestAlignedLba, LogicalBlocksPerPhysicalBlock and OptimalTransferLengthGranularity must be 0
1150 // for logical partitions.
1152 if (Private
->BlockIo
.Revision
>= EFI_BLOCK_IO_PROTOCOL_REVISION2
) {
1153 Private
->Media
.LowestAlignedLba
= 0;
1154 Private
->Media
.LogicalBlocksPerPhysicalBlock
= 0;
1155 Private
->Media2
.LowestAlignedLba
= 0;
1156 Private
->Media2
.LogicalBlocksPerPhysicalBlock
= 0;
1157 if (Private
->BlockIo
.Revision
>= EFI_BLOCK_IO_PROTOCOL_REVISION3
) {
1158 Private
->Media
.OptimalTransferLengthGranularity
= 0;
1159 Private
->Media2
.OptimalTransferLengthGranularity
= 0;
1163 Private
->DevicePath
= AppendDevicePathNode (ParentDevicePath
, DevicePathNode
);
1165 if (Private
->DevicePath
== NULL
) {
1167 return EFI_OUT_OF_RESOURCES
;
1170 if (InstallEspGuid
) {
1171 Private
->EspGuid
= &gEfiPartTypeSystemPartGuid
;
1174 // If NULL InstallMultipleProtocolInterfaces will ignore it.
1176 Private
->EspGuid
= NULL
;
1180 // Create the new handle.
1182 Private
->Handle
= NULL
;
1183 if (Private
->DiskIo2
!= NULL
) {
1184 Status
= gBS
->InstallMultipleProtocolInterfaces (
1186 &gEfiDevicePathProtocolGuid
,
1187 Private
->DevicePath
,
1188 &gEfiBlockIoProtocolGuid
,
1190 &gEfiBlockIo2ProtocolGuid
,
1197 Status
= gBS
->InstallMultipleProtocolInterfaces (
1199 &gEfiDevicePathProtocolGuid
,
1200 Private
->DevicePath
,
1201 &gEfiBlockIoProtocolGuid
,
1209 if (!EFI_ERROR (Status
)) {
1211 // Open the Parent Handle for the child
1213 Status
= gBS
->OpenProtocol (
1215 &gEfiDiskIoProtocolGuid
,
1216 (VOID
**) &ParentDiskIo
,
1217 This
->DriverBindingHandle
,
1219 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1222 FreePool (Private
->DevicePath
);
1231 The user Entry Point for module Partition. The user code starts with this function.
1233 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1234 @param[in] SystemTable A pointer to the EFI System Table.
1236 @retval EFI_SUCCESS The entry point is executed successfully.
1237 @retval other Some error occurs when executing this entry point.
1242 InitializePartition (
1243 IN EFI_HANDLE ImageHandle
,
1244 IN EFI_SYSTEM_TABLE
*SystemTable
1250 // Install driver model protocol(s).
1252 Status
= EfiLibInstallDriverBindingComponentName2 (
1255 &gPartitionDriverBinding
,
1257 &gPartitionComponentName
,
1258 &gPartitionComponentName2
1260 ASSERT_EFI_ERROR (Status
);