2 Partition driver that produces logical BlockIo devices from a physical
3 BlockIo device. The logical BlockIo devices are based on the format
4 of the raw block devices media. Currently "El Torito CD-ROM", Legacy
5 MBR, and GPT partition schemes are supported.
7 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
8 This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 #include "Partition.h"
22 // Partition Driver Global Variables.
24 EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding
= {
25 PartitionDriverBindingSupported
,
26 PartitionDriverBindingStart
,
27 PartitionDriverBindingStop
,
34 // Prioritized function list to detect partition table.
36 PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable
[] = {
37 PartitionInstallGptChildHandles
,
38 PartitionInstallElToritoChildHandles
,
39 PartitionInstallMbrChildHandles
,
44 Test to see if this driver supports ControllerHandle. Any ControllerHandle
45 than contains a BlockIo and DiskIo protocol or a BlockIo2 protocol can be
48 @param[in] This Protocol instance pointer.
49 @param[in] ControllerHandle Handle of device to test.
50 @param[in] RemainingDevicePath Optional parameter use to pick a specific child
53 @retval EFI_SUCCESS This driver supports this device
54 @retval EFI_ALREADY_STARTED This driver is already running on this device
55 @retval other This driver does not support this device
60 PartitionDriverBindingSupported (
61 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
62 IN EFI_HANDLE ControllerHandle
,
63 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
67 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
68 EFI_DISK_IO_PROTOCOL
*DiskIo
;
72 // Check RemainingDevicePath validation
74 if (RemainingDevicePath
!= NULL
) {
76 // Check if RemainingDevicePath is the End of Device Path Node,
77 // if yes, go on checking other conditions
79 if (!IsDevicePathEnd (RemainingDevicePath
)) {
81 // If RemainingDevicePath isn't the End of Device Path Node,
82 // check its validation
84 Node
= (EFI_DEV_PATH
*) RemainingDevicePath
;
85 if (Node
->DevPath
.Type
!= MEDIA_DEVICE_PATH
||
86 Node
->DevPath
.SubType
!= MEDIA_HARDDRIVE_DP
||
87 DevicePathNodeLength (&Node
->DevPath
) != sizeof (HARDDRIVE_DEVICE_PATH
)) {
88 return EFI_UNSUPPORTED
;
94 // Open the IO Abstraction(s) needed to perform the supported test
96 Status
= gBS
->OpenProtocol (
98 &gEfiDiskIoProtocolGuid
,
100 This
->DriverBindingHandle
,
102 EFI_OPEN_PROTOCOL_BY_DRIVER
104 if (Status
== EFI_ALREADY_STARTED
) {
107 if (EFI_ERROR (Status
)) {
111 // Close the I/O Abstraction(s) used to perform the supported test
115 &gEfiDiskIoProtocolGuid
,
116 This
->DriverBindingHandle
,
121 // Open the EFI Device Path protocol needed to perform the supported test
123 Status
= gBS
->OpenProtocol (
125 &gEfiDevicePathProtocolGuid
,
126 (VOID
**) &ParentDevicePath
,
127 This
->DriverBindingHandle
,
129 EFI_OPEN_PROTOCOL_BY_DRIVER
131 if (Status
== EFI_ALREADY_STARTED
) {
135 if (EFI_ERROR (Status
)) {
140 // Close protocol, don't use device path protocol in the Support() function
144 &gEfiDevicePathProtocolGuid
,
145 This
->DriverBindingHandle
,
150 // Open the IO Abstraction(s) needed to perform the supported test
152 Status
= gBS
->OpenProtocol (
154 &gEfiBlockIoProtocolGuid
,
156 This
->DriverBindingHandle
,
158 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
160 if (EFI_ERROR (Status
)) {
164 Status
= gBS
->OpenProtocol (
166 &gEfiBlockIo2ProtocolGuid
,
168 This
->DriverBindingHandle
,
170 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
172 if (EFI_ERROR (Status
)) {
174 // According to UEFI Spec 2.3.1, if a driver is written for a disk device,
175 // then the EFI_BLOCK_IO_PROTOCOL and EFI_BLOCK_IO2_PROTOCOAL must be implemented.
176 // Currently, SCSI disk driver only produce the EFI_BLOCK_IO_PROTOCOL, it will
177 // not be updated until the non blocking SCSI Pass Thru Protocol is provided.
178 // If there is no EFI_BLOCK_IO2_PROTOCOL, skip here.
185 Start this driver on ControllerHandle by opening a Block IO or a Block IO2
186 or both, and Disk IO protocol, reading Device Path, and creating a child
187 handle with a Disk IO and device path protocol.
189 @param[in] This Protocol instance pointer.
190 @param[in] ControllerHandle Handle of device to bind driver to
191 @param[in] RemainingDevicePath Optional parameter use to pick a specific child
194 @retval EFI_SUCCESS This driver is added to ControllerHandle
195 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
196 @retval other This driver does not support this device
201 PartitionDriverBindingStart (
202 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
203 IN EFI_HANDLE ControllerHandle
,
204 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
208 EFI_STATUS OpenStatus
;
209 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
210 EFI_BLOCK_IO2_PROTOCOL
*BlockIo2
;
211 EFI_DISK_IO_PROTOCOL
*DiskIo
;
212 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
213 PARTITION_DETECT_ROUTINE
*Routine
;
214 BOOLEAN MediaPresent
;
217 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
219 // Check RemainingDevicePath validation
221 if (RemainingDevicePath
!= NULL
) {
223 // Check if RemainingDevicePath is the End of Device Path Node,
224 // if yes, return EFI_SUCCESS
226 if (IsDevicePathEnd (RemainingDevicePath
)) {
227 Status
= EFI_SUCCESS
;
233 // Try to open BlockIO and BlockIO2. If BlockIO would be opened, continue,
234 // otherwise, return error.
236 Status
= gBS
->OpenProtocol (
238 &gEfiBlockIoProtocolGuid
,
240 This
->DriverBindingHandle
,
242 EFI_OPEN_PROTOCOL_GET_PROTOCOL
244 if (EFI_ERROR (Status
)) {
248 Status
= gBS
->OpenProtocol (
250 &gEfiBlockIo2ProtocolGuid
,
252 This
->DriverBindingHandle
,
254 EFI_OPEN_PROTOCOL_BY_DRIVER
256 if (EFI_ERROR (Status
)) {
258 // According to UEFI Spec 2.3.1, if a driver is written for a disk device,
259 // then the EFI_BLOCK_IO_PROTOCOL and EFI_BLOCK_IO2_PROTOCOAL must be implemented.
260 // Currently, SCSI disk driver only produce the EFI_BLOCK_IO_PROTOCOL, it will
261 // not be updated until the non blocking SCSI Pass Thru Protocol is provided.
262 // If there is no EFI_BLOCK_IO2_PROTOCOL, skip here.
267 // Get the Device Path Protocol on ControllerHandle's handle.
269 Status
= gBS
->OpenProtocol (
271 &gEfiDevicePathProtocolGuid
,
272 (VOID
**) &ParentDevicePath
,
273 This
->DriverBindingHandle
,
275 EFI_OPEN_PROTOCOL_BY_DRIVER
277 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
281 Status
= gBS
->OpenProtocol (
283 &gEfiDiskIoProtocolGuid
,
285 This
->DriverBindingHandle
,
287 EFI_OPEN_PROTOCOL_BY_DRIVER
289 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
292 &gEfiDevicePathProtocolGuid
,
293 This
->DriverBindingHandle
,
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 El Torito, and then legacy MBR partition types. If the
310 // media supports a given partition type install child handles to represent
311 // the partitions described by the media.
313 Routine
= &mPartitionDetectRoutineTable
[0];
314 while (*Routine
!= NULL
) {
315 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 BlockIO2 if has.
356 &gEfiBlockIo2ProtocolGuid
,
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 &gEfiBlockIo2ProtocolGuid
,
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
581 // Read 1 byte from offset 0 but passing NULL as buffer pointer
583 Status
= DiskIo
->ReadDisk (DiskIo
, MediaId
, 0, 1, NULL
);
584 if ((Status
== EFI_NO_MEDIA
) || (Status
== EFI_MEDIA_CHANGED
)) {
587 return DefaultStatus
;
591 Read by using the Disk IO protocol on the parent device. Lba addresses
592 must be converted to byte offsets.
594 @param This Protocol instance pointer.
595 @param MediaId Id of the media, changes every time the media is replaced.
596 @param Lba The starting Logical Block Address to read from
597 @param BufferSize Size of Buffer, must be a multiple of device block size.
598 @param Buffer Buffer containing read data
600 @retval EFI_SUCCESS The data was read correctly from the device.
601 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
602 @retval EFI_NO_MEDIA There is no media in the device.
603 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
604 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
605 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
606 valid for the device.
611 PartitionReadBlocks (
612 IN EFI_BLOCK_IO_PROTOCOL
*This
,
619 PARTITION_PRIVATE_DATA
*Private
;
622 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
624 if (BufferSize
% Private
->BlockSize
!= 0) {
625 return ProbeMediaStatus (Private
->DiskIo
, MediaId
, EFI_BAD_BUFFER_SIZE
);
628 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
629 if (Offset
+ BufferSize
> Private
->End
) {
630 return ProbeMediaStatus (Private
->DiskIo
, MediaId
, EFI_INVALID_PARAMETER
);
633 // Because some kinds of partition have different block size from their parent
634 // device, we call the Disk IO protocol on the parent device, not the Block IO
637 return Private
->DiskIo
->ReadDisk (Private
->DiskIo
, MediaId
, Offset
, BufferSize
, Buffer
);
641 Write by using the Disk IO protocol on the parent device. Lba addresses
642 must be converted to byte offsets.
644 @param[in] This Protocol instance pointer.
645 @param[in] MediaId Id of the media, changes every time the media is replaced.
646 @param[in] Lba The starting Logical Block Address to read from
647 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
648 @param[in] Buffer Buffer containing data to be written to device.
650 @retval EFI_SUCCESS The data was written correctly to the device.
651 @retval EFI_WRITE_PROTECTED The device can not be written to.
652 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
653 @retval EFI_NO_MEDIA There is no media in the device.
654 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
655 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
656 @retval EFI_INVALID_PARAMETER The write request contains a LBA that is not
657 valid for the device.
662 PartitionWriteBlocks (
663 IN EFI_BLOCK_IO_PROTOCOL
*This
,
670 PARTITION_PRIVATE_DATA
*Private
;
673 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
675 if (BufferSize
% Private
->BlockSize
!= 0) {
676 return ProbeMediaStatus (Private
->DiskIo
, MediaId
, EFI_BAD_BUFFER_SIZE
);
679 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
680 if (Offset
+ BufferSize
> Private
->End
) {
681 return ProbeMediaStatus (Private
->DiskIo
, MediaId
, EFI_INVALID_PARAMETER
);
684 // Because some kinds of partition have different block size from their parent
685 // device, we call the Disk IO protocol on the parent device, not the Block IO
688 return Private
->DiskIo
->WriteDisk (Private
->DiskIo
, MediaId
, Offset
, BufferSize
, Buffer
);
693 Flush the parent Block Device.
695 @param This Protocol instance pointer.
697 @retval EFI_SUCCESS All outstanding data was written to the device
698 @retval EFI_DEVICE_ERROR The device reported an error while writting back the data
699 @retval EFI_NO_MEDIA There is no media in the device.
704 PartitionFlushBlocks (
705 IN EFI_BLOCK_IO_PROTOCOL
*This
708 PARTITION_PRIVATE_DATA
*Private
;
710 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
712 return Private
->ParentBlockIo
->FlushBlocks (Private
->ParentBlockIo
);
716 Reset the Block Device throught Block I/O2 protocol.
718 @param This Protocol instance pointer.
719 @param ExtendedVerification Driver may perform diagnostics on reset.
721 @retval EFI_SUCCESS The device was reset.
722 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
729 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
730 IN BOOLEAN ExtendedVerification
733 PARTITION_PRIVATE_DATA
*Private
;
735 Private
= PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This
);
737 return Private
->ParentBlockIo2
->Reset (
738 Private
->ParentBlockIo2
,
744 Read BufferSize bytes from Lba into Buffer.
746 This function reads the requested number of blocks from the device. All the
747 blocks are read, or an error is returned.
748 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and
749 non-blocking I/O is being used, the Event associated with this request will
752 @param[in] This Indicates a pointer to the calling context.
753 @param[in] MediaId Id of the media, changes every time the media is
755 @param[in] Lba The starting Logical Block Address to read from.
756 @param[in, out] Token A pointer to the token associated with the transaction.
757 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
758 @param[out] Buffer A pointer to the destination buffer for the data. The
759 caller is responsible for either having implicit or
760 explicit ownership of the buffer.
762 @retval EFI_SUCCESS The read request was queued if Token->Event is
763 not NULL.The data was read correctly from the
764 device if the Token->Event is NULL.
765 @retval EFI_DEVICE_ERROR The device reported an error while performing
767 @retval EFI_NO_MEDIA There is no media in the device.
768 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
769 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
770 intrinsic block size of the device.
771 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
772 or the buffer is not on proper alignment.
773 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
778 PartitionReadBlocksEx (
779 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
782 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
787 PARTITION_PRIVATE_DATA
*Private
;
792 return EFI_INVALID_PARAMETER
;
795 Private
= PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This
);
796 if (BufferSize
% Private
->BlockSize
!= 0) {
797 return EFI_BAD_BUFFER_SIZE
;
800 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
801 if (Offset
+ BufferSize
> Private
->End
) {
802 return EFI_INVALID_PARAMETER
;
806 // Since the BlockIO2 call Parent BlockIO2 directly, so here the offset must
807 // be multiple of BlockSize. If the Spec will be updated the DiskIO to support
808 // BlockIO2, this limitation will be removed and call DiskIO here.
810 Lba
= DivU64x32Remainder (Offset
, Private
->BlockSize
, &UnderRun
);
812 return EFI_UNSUPPORTED
;
816 // Because some partitions have different block size from their parent
817 // device, in that case the Block I/O2 couldn't be called.
819 if (Private
->BlockSize
!= Private
->ParentBlockIo
->Media
->BlockSize
) {
820 return EFI_UNSUPPORTED
;
823 return Private
->ParentBlockIo2
->ReadBlocksEx (Private
->ParentBlockIo2
, MediaId
, Lba
, Token
, BufferSize
, Buffer
);
827 Write BufferSize bytes from Lba into Buffer.
829 This function writes the requested number of blocks to the device. All blocks
830 are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
831 EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
832 being used, the Event associated with this request will not be signaled.
834 @param[in] This Indicates a pointer to the calling context.
835 @param[in] MediaId The media ID that the write request is for.
836 @param[in] Lba The starting logical block address to be written. The
837 caller is responsible for writing to only legitimate
839 @param[in, out] Token A pointer to the token associated with the transaction.
840 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
841 @param[in] Buffer A pointer to the source buffer for the data.
843 @retval EFI_SUCCESS The write request was queued if Event is not NULL.
844 The data was written correctly to the device if
846 @retval EFI_WRITE_PROTECTED The device can not be written to.
847 @retval EFI_NO_MEDIA There is no media in the device.
848 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
849 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
850 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
851 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
852 or the buffer is not on proper alignment.
853 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
859 PartitionWriteBlocksEx (
860 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
863 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
868 PARTITION_PRIVATE_DATA
*Private
;
873 return EFI_INVALID_PARAMETER
;
876 Private
= PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This
);
877 if (BufferSize
% Private
->BlockSize
!= 0) {
878 return EFI_BAD_BUFFER_SIZE
;
881 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
882 if (Offset
+ BufferSize
> Private
->End
) {
883 return EFI_INVALID_PARAMETER
;
887 // Since the BlockIO2 call Parent BlockIO2 directly, so here the offset must
888 // be multiple of BlockSize. If the Spec will be updated the DiskIO to support
889 // BlockIO2, this limitation will be removed and call DiskIO here.
891 Lba
= DivU64x32Remainder (Offset
, Private
->BlockSize
, &UnderRun
);
893 return EFI_UNSUPPORTED
;
897 // Because some kinds of partition have different block size from their parent,
898 // in that case it couldn't call parent Block I/O2.
900 if (Private
->BlockSize
!= Private
->ParentBlockIo
->Media
->BlockSize
) {
901 return EFI_UNSUPPORTED
;
904 return Private
->ParentBlockIo2
->WriteBlocksEx (Private
->ParentBlockIo2
, MediaId
, Lba
, Token
, BufferSize
, Buffer
);
908 Flush the Block Device.
910 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED
911 is returned and non-blocking I/O is being used, the Event associated with
912 this request will not be signaled.
914 @param[in] This Indicates a pointer to the calling context.
915 @param[in, out] Token A pointer to the token associated with the transaction
917 @retval EFI_SUCCESS The flush request was queued if Event is not NULL.
918 All outstanding data was written correctly to the
919 device if the Event is NULL.
920 @retval EFI_DEVICE_ERROR The device reported an error while writting back
922 @retval EFI_WRITE_PROTECTED The device cannot be written to.
923 @retval EFI_NO_MEDIA There is no media in the device.
924 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
925 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
931 PartitionFlushBlocksEx (
932 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
933 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
936 PARTITION_PRIVATE_DATA
*Private
;
938 Private
= PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This
);
941 // Because some kinds of partition have different block size from their parent,
942 // in that case it couldn't call parent Block I/O2.
944 if (Private
->BlockSize
!= Private
->ParentBlockIo
->Media
->BlockSize
) {
945 return EFI_UNSUPPORTED
;
948 return Private
->ParentBlockIo2
->FlushBlocksEx (Private
->ParentBlockIo2
, Token
);
953 Create a child handle for a logical block device that represents the
954 bytes Start to End of the Parent Block IO device.
956 @param[in] This Protocol instance pointer.
957 @param[in] ParentHandle Parent Handle for new child.
958 @param[in] ParentDiskIo Parent DiskIo interface.
959 @param[in] ParentBlockIo Parent BlockIo interface.
960 @param[in] ParentBlockIo2 Parent BlockIo2 interface.
961 @param[in] ParentDevicePath Parent Device Path.
962 @param[in] DevicePathNode Child Device Path node.
963 @param[in] Start Start Block.
964 @param[in] End End Block.
965 @param[in] BlockSize Child block size.
966 @param[in] InstallEspGuid Flag to install EFI System Partition GUID on handle.
968 @retval EFI_SUCCESS A child handle was added.
969 @retval other A child handle was not added.
973 PartitionInstallChildHandle (
974 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
975 IN EFI_HANDLE ParentHandle
,
976 IN EFI_DISK_IO_PROTOCOL
*ParentDiskIo
,
977 IN EFI_BLOCK_IO_PROTOCOL
*ParentBlockIo
,
978 IN EFI_BLOCK_IO2_PROTOCOL
*ParentBlockIo2
,
979 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
980 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
,
984 IN BOOLEAN InstallEspGuid
988 PARTITION_PRIVATE_DATA
*Private
;
990 Status
= EFI_SUCCESS
;
991 Private
= AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA
));
992 if (Private
== NULL
) {
993 return EFI_OUT_OF_RESOURCES
;
996 Private
->Signature
= PARTITION_PRIVATE_DATA_SIGNATURE
;
998 Private
->Start
= MultU64x32 (Start
, ParentBlockIo
->Media
->BlockSize
);
999 Private
->End
= MultU64x32 (End
+ 1, ParentBlockIo
->Media
->BlockSize
);
1001 Private
->BlockSize
= BlockSize
;
1002 Private
->ParentBlockIo
= ParentBlockIo
;
1003 Private
->ParentBlockIo2
= ParentBlockIo2
;
1004 Private
->DiskIo
= ParentDiskIo
;
1007 // Set the BlockIO into Private Data.
1009 Private
->BlockIo
.Revision
= ParentBlockIo
->Revision
;
1011 Private
->BlockIo
.Media
= &Private
->Media
;
1012 CopyMem (Private
->BlockIo
.Media
, ParentBlockIo
->Media
, sizeof (EFI_BLOCK_IO_MEDIA
));
1014 Private
->BlockIo
.Reset
= PartitionReset
;
1015 Private
->BlockIo
.ReadBlocks
= PartitionReadBlocks
;
1016 Private
->BlockIo
.WriteBlocks
= PartitionWriteBlocks
;
1017 Private
->BlockIo
.FlushBlocks
= PartitionFlushBlocks
;
1020 // Set the BlockIO2 into Private Data.
1022 if (Private
->ParentBlockIo2
!= NULL
) {
1023 Private
->BlockIo2
.Media
= &Private
->Media2
;
1024 CopyMem (Private
->BlockIo2
.Media
, ParentBlockIo2
->Media
, sizeof (EFI_BLOCK_IO_MEDIA
));
1026 Private
->BlockIo2
.Reset
= PartitionResetEx
;
1027 Private
->BlockIo2
.ReadBlocksEx
= PartitionReadBlocksEx
;
1028 Private
->BlockIo2
.WriteBlocksEx
= PartitionWriteBlocksEx
;
1029 Private
->BlockIo2
.FlushBlocksEx
= PartitionFlushBlocksEx
;
1032 Private
->Media
.IoAlign
= 0;
1033 Private
->Media
.LogicalPartition
= TRUE
;
1034 Private
->Media
.LastBlock
= DivU64x32 (
1037 ParentBlockIo
->Media
->BlockSize
1042 Private
->Media
.BlockSize
= (UINT32
) BlockSize
;
1045 // For BlockIO2, it should keep the same alignment with the parent BlockIO2's.
1047 Private
->Media2
.LogicalPartition
= TRUE
;
1048 Private
->Media2
.LastBlock
= Private
->Media
.LastBlock
;
1049 Private
->Media2
.BlockSize
= (UINT32
) BlockSize
;
1052 // Per UEFI Spec, LowestAlignedLba and LogicalBlocksPerPhysicalBlock must be 0
1053 // for logical partitions.
1055 if (Private
->BlockIo
.Revision
>= EFI_BLOCK_IO_PROTOCOL_REVISION2
) {
1056 Private
->BlockIo
.Media
->LowestAlignedLba
= 0;
1057 Private
->BlockIo
.Media
->LogicalBlocksPerPhysicalBlock
= 0;
1060 Private
->DevicePath
= AppendDevicePathNode (ParentDevicePath
, DevicePathNode
);
1062 if (Private
->DevicePath
== NULL
) {
1064 return EFI_OUT_OF_RESOURCES
;
1067 if (InstallEspGuid
) {
1068 Private
->EspGuid
= &gEfiPartTypeSystemPartGuid
;
1071 // If NULL InstallMultipleProtocolInterfaces will ignore it.
1073 Private
->EspGuid
= NULL
;
1077 // Create the new handle.
1078 // BlockIO2 will be installed on the condition that the blocksize of parent BlockIO
1079 // is same with the child BlockIO's. Instead of calling the DiskIO, the child BlockIO2
1080 // directly call the parent BlockIO and doesn't handle the different block size issue.
1081 // If SPEC will update the DiskIO to support the Non-Blocking model, the BlockIO2 will call
1082 // DiskIO to handle the blocksize unequal issue and the limitation will be remove from
1085 Private
->Handle
= NULL
;
1086 if ((Private
->ParentBlockIo2
!= NULL
) &&
1087 (Private
->ParentBlockIo2
->Media
->BlockSize
== BlockSize
)
1089 Status
= gBS
->InstallMultipleProtocolInterfaces (
1091 &gEfiDevicePathProtocolGuid
,
1092 Private
->DevicePath
,
1093 &gEfiBlockIoProtocolGuid
,
1095 &gEfiBlockIo2ProtocolGuid
,
1102 Status
= gBS
->InstallMultipleProtocolInterfaces (
1104 &gEfiDevicePathProtocolGuid
,
1105 Private
->DevicePath
,
1106 &gEfiBlockIoProtocolGuid
,
1114 if (!EFI_ERROR (Status
)) {
1116 // Open the Parent Handle for the child
1118 Status
= gBS
->OpenProtocol (
1120 &gEfiDiskIoProtocolGuid
,
1121 (VOID
**) &ParentDiskIo
,
1122 This
->DriverBindingHandle
,
1124 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1127 FreePool (Private
->DevicePath
);
1136 The user Entry Point for module Partition. The user code starts with this function.
1138 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1139 @param[in] SystemTable A pointer to the EFI System Table.
1141 @retval EFI_SUCCESS The entry point is executed successfully.
1142 @retval other Some error occurs when executing this entry point.
1147 InitializePartition (
1148 IN EFI_HANDLE ImageHandle
,
1149 IN EFI_SYSTEM_TABLE
*SystemTable
1155 // Install driver model protocol(s).
1157 Status
= EfiLibInstallDriverBindingComponentName2 (
1160 &gPartitionDriverBinding
,
1162 &gPartitionComponentName
,
1163 &gPartitionComponentName2
1165 ASSERT_EFI_ERROR (Status
);