summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c
diff options
context:
space:
mode:
Diffstat (limited to 'MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c')
-rw-r--r--MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c612
1 files changed, 502 insertions, 110 deletions
diff --git a/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c b/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c
index 3596a3bfc1..7d194daaea 100644
--- a/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c
+++ b/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c
@@ -40,16 +40,15 @@ PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable[] = {
NULL
};
-
-
/**
Test to see if this driver supports ControllerHandle. Any ControllerHandle
- than contains a BlockIo and DiskIo protocol can be supported.
+ than contains a BlockIo and DiskIo protocol or a BlockIo2 protocol can be
+ supported.
- @param This Protocol instance pointer.
- @param ControllerHandle Handle of device to test
- @param RemainingDevicePath Optional parameter use to pick a specific child
- device to start.
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to test.
+ @param[in] RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
@retval EFI_SUCCESS This driver supports this device
@retval EFI_ALREADY_STARTED This driver is already running on this device
@@ -86,7 +85,7 @@ PartitionDriverBindingSupported (
if (Node->DevPath.Type != MEDIA_DEVICE_PATH ||
Node->DevPath.SubType != MEDIA_HARDDRIVE_DP ||
DevicePathNodeLength (&Node->DevPath) != sizeof (HARDDRIVE_DEVICE_PATH)) {
- return EFI_UNSUPPORTED;
+ return EFI_UNSUPPORTED;
}
}
}
@@ -105,7 +104,6 @@ PartitionDriverBindingSupported (
if (Status == EFI_ALREADY_STARTED) {
return EFI_SUCCESS;
}
-
if (EFI_ERROR (Status)) {
return Status;
}
@@ -159,20 +157,39 @@ PartitionDriverBindingSupported (
ControllerHandle,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
-
- return Status;
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiBlockIo2ProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // According to UEFI Spec 2.3.1, if a driver is written for a disk device,
+ // then the EFI_BLOCK_IO_PROTOCOL and EFI_BLOCK_IO2_PROTOCOAL must be implemented.
+ // Currently, SCSI disk driver only produce the EFI_BLOCK_IO_PROTOCOL, it will
+ // not be updated until the non blocking SCSI Pass Thru Protocol is provided.
+ // If there is no EFI_BLOCK_IO2_PROTOCOL, skip here.
+ //
+ }
+ return EFI_SUCCESS;
}
-
/**
- Start this driver on ControllerHandle by opening a Block IO and Disk IO
- protocol, reading Device Path, and creating a child handle with a
- Disk IO and device path protocol.
+ Start this driver on ControllerHandle by opening a Block IO or a Block IO2
+ or both, and Disk IO protocol, reading Device Path, and creating a child
+ handle with a Disk IO and device path protocol.
- @param This Protocol instance pointer.
- @param ControllerHandle Handle of device to bind driver to
- @param RemainingDevicePath Optional parameter use to pick a specific child
- device to start.
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to bind driver to
+ @param[in] RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
@retval EFI_SUCCESS This driver is added to ControllerHandle
@retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
@@ -190,6 +207,7 @@ PartitionDriverBindingStart (
EFI_STATUS Status;
EFI_STATUS OpenStatus;
EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
EFI_DISK_IO_PROTOCOL *DiskIo;
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
PARTITION_DETECT_ROUTINE *Routine;
@@ -211,6 +229,10 @@ PartitionDriverBindingStart (
}
}
+ //
+ // Try to open BlockIO and BlockIO2. If BlockIO would be opened, continue,
+ // otherwise, return error.
+ //
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiBlockIoProtocolGuid,
@@ -222,8 +244,27 @@ PartitionDriverBindingStart (
if (EFI_ERROR (Status)) {
goto Exit;
}
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiBlockIo2ProtocolGuid,
+ (VOID **) &BlockIo2,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // According to UEFI Spec 2.3.1, if a driver is written for a disk device,
+ // then the EFI_BLOCK_IO_PROTOCOL and EFI_BLOCK_IO2_PROTOCOAL must be implemented.
+ // Currently, SCSI disk driver only produce the EFI_BLOCK_IO_PROTOCOL, it will
+ // not be updated until the non blocking SCSI Pass Thru Protocol is provided.
+ // If there is no EFI_BLOCK_IO2_PROTOCOL, skip here.
+ //
+ }
+
//
- // Get the Device Path Protocol on ControllerHandle's handle
+ // Get the Device Path Protocol on ControllerHandle's handle.
//
Status = gBS->OpenProtocol (
ControllerHandle,
@@ -276,6 +317,7 @@ PartitionDriverBindingStart (
ControllerHandle,
DiskIo,
BlockIo,
+ BlockIo2,
ParentDevicePath
);
if (!EFI_ERROR (Status) || Status == EFI_MEDIA_CHANGED || Status == EFI_NO_MEDIA) {
@@ -306,6 +348,15 @@ PartitionDriverBindingStart (
This->DriverBindingHandle,
ControllerHandle
);
+ //
+ // Close Parent BlockIO2 if has.
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiBlockIo2ProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
gBS->CloseProtocol (
ControllerHandle,
@@ -320,7 +371,6 @@ Exit:
return Status;
}
-
/**
Stop this driver on ControllerHandle. Support stopping any child handles
created by this driver.
@@ -347,10 +397,15 @@ PartitionDriverBindingStop (
EFI_STATUS Status;
UINTN Index;
EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
BOOLEAN AllChildrenStopped;
PARTITION_PRIVATE_DATA *Private;
EFI_DISK_IO_PROTOCOL *DiskIo;
+ BlockIo = NULL;
+ BlockIo2 = NULL;
+ Private = NULL;
+
if (NumberOfChildren == 0) {
//
// Close the bus driver
@@ -361,6 +416,15 @@ PartitionDriverBindingStop (
This->DriverBindingHandle,
ControllerHandle
);
+ //
+ // Close Parent BlockIO2 if has.
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiBlockIo2ProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
gBS->CloseProtocol (
ControllerHandle,
@@ -368,60 +432,91 @@ PartitionDriverBindingStop (
This->DriverBindingHandle,
ControllerHandle
);
-
return EFI_SUCCESS;
}
AllChildrenStopped = TRUE;
for (Index = 0; Index < NumberOfChildren; Index++) {
- Status = gBS->OpenProtocol (
- ChildHandleBuffer[Index],
- &gEfiBlockIoProtocolGuid,
- (VOID **) &BlockIo,
- This->DriverBindingHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- if (!EFI_ERROR (Status)) {
-
+ gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ //
+ // Try to locate BlockIo2.
+ //
+ gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiBlockIo2ProtocolGuid,
+ (VOID **) &BlockIo2,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (BlockIo != NULL) {
Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo);
+ } else if (BlockIo2 != NULL) {
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (BlockIo2);
+ } else {
+ ASSERT (FALSE);
+ }
- //
- // All Software protocols have be freed from the handle so remove it.
- //
+ Status = gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index]
+ );
+ //
+ // All Software protocols have be freed from the handle so remove it.
+ // Remove the BlockIo Protocol if has.
+ // Remove the BlockIo2 Protocol if has.
+ //
+ if (BlockIo2 != NULL) {
BlockIo->FlushBlocks (BlockIo);
-
- Status = gBS->CloseProtocol (
- ControllerHandle,
- &gEfiDiskIoProtocolGuid,
- This->DriverBindingHandle,
- ChildHandleBuffer[Index]
- );
-
+ BlockIo2->FlushBlocksEx (BlockIo2, NULL);
Status = gBS->UninstallMultipleProtocolInterfaces (
- ChildHandleBuffer[Index],
- &gEfiDevicePathProtocolGuid,
- Private->DevicePath,
- &gEfiBlockIoProtocolGuid,
- &Private->BlockIo,
- Private->EspGuid,
- NULL,
- NULL
- );
- if (EFI_ERROR (Status)) {
- gBS->OpenProtocol (
- ControllerHandle,
- &gEfiDiskIoProtocolGuid,
- (VOID **) &DiskIo,
- This->DriverBindingHandle,
- ChildHandleBuffer[Index],
- EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
- );
- } else {
- FreePool (Private->DevicePath);
- FreePool (Private);
- }
+ ChildHandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ Private->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &Private->BlockIo,
+ &gEfiBlockIo2ProtocolGuid,
+ &Private->BlockIo2,
+ Private->EspGuid,
+ NULL,
+ NULL
+ );
+ } else {
+ BlockIo->FlushBlocks (BlockIo);
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ Private->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &Private->BlockIo,
+ Private->EspGuid,
+ NULL,
+ NULL
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ (VOID **) &DiskIo,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index],
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ } else {
+ FreePool (Private->DevicePath);
+ FreePool (Private);
}
if (EFI_ERROR (Status)) {
@@ -551,11 +646,11 @@ PartitionReadBlocks (
Write by using the Disk IO protocol on the parent device. Lba addresses
must be converted to byte offsets.
- @param This Protocol instance pointer.
- @param MediaId Id of the media, changes every time the media is replaced.
- @param Lba The starting Logical Block Address to read from
- @param BufferSize Size of Buffer, must be a multiple of device block size.
- @param Buffer Buffer containing read data
+ @param[in] This Protocol instance pointer.
+ @param[in] MediaId Id of the media, changes every time the media is replaced.
+ @param[in] Lba The starting Logical Block Address to read from
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[in] Buffer Buffer containing data to be written to device.
@retval EFI_SUCCESS The data was written correctly to the device.
@retval EFI_WRITE_PROTECTED The device can not be written to.
@@ -574,7 +669,7 @@ PartitionWriteBlocks (
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN UINTN BufferSize,
- OUT VOID *Buffer
+ IN VOID *Buffer
)
{
PARTITION_PRIVATE_DATA *Private;
@@ -622,25 +717,261 @@ PartitionFlushBlocks (
return Private->ParentBlockIo->FlushBlocks (Private->ParentBlockIo);
}
+/**
+ Reset the Block Device throught Block I/O2 protocol.
+
+ @param This Protocol instance pointer.
+ @param ExtendedVerification Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could
+ not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionResetEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ PARTITION_PRIVATE_DATA *Private;
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
+
+ return Private->ParentBlockIo2->Reset (
+ Private->ParentBlockIo2,
+ ExtendedVerification
+ );
+}
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ This function reads the requested number of blocks from the device. All the
+ blocks are read, or an error is returned.
+ If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and
+ non-blocking I/O is being used, the Event associated with this request will
+ not be signaled.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId Id of the media, changes every time the media is
+ replaced.
+ @param[in] Lba The starting Logical Block Address to read from.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[out] Buffer A pointer to the destination buffer for the data. The
+ caller is responsible for either having implicit or
+ explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The read request was queued if Token->Event is
+ not NULL.The data was read correctly from the
+ device if the Token->Event is NULL.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing
+ the read.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
+ intrinsic block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
+ of resources.
+**/
+EFI_STATUS
+EFIAPI
+PartitionReadBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ PARTITION_PRIVATE_DATA *Private;
+ UINT64 Offset;
+ UINT32 UnderRun;
+
+ if (Token == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
+ if (BufferSize % Private->BlockSize != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
+ if (Offset + BufferSize > Private->End) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Since the BlockIO2 call Parent BlockIO2 directly, so here the offset must
+ // be multiple of BlockSize. If the Spec will be updated the DiskIO to support
+ // BlockIO2, this limitation will be removed and call DiskIO here.
+ //
+ Lba = DivU64x32Remainder (Offset, Private->BlockSize, &UnderRun);
+ if (UnderRun != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Because some partitions have different block size from their parent
+ // device, in that case the Block I/O2 couldn't be called.
+ //
+ if (Private->BlockSize != Private->ParentBlockIo->Media->BlockSize) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return Private->ParentBlockIo2->ReadBlocksEx (Private->ParentBlockIo2, MediaId, Lba, Token, BufferSize, Buffer);
+}
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ This function writes the requested number of blocks to the device. All blocks
+ are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
+ EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
+ being used, the Event associated with this request will not be signaled.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the write request is for.
+ @param[in] Lba The starting logical block address to be written. The
+ caller is responsible for writing to only legitimate
+ locations.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[in] Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The write request was queued if Event is not NULL.
+ The data was written correctly to the device if
+ the Event is NULL.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
+ of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionWriteBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ PARTITION_PRIVATE_DATA *Private;
+ UINT64 Offset;
+ UINT32 UnderRun;
+
+ if (Token == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
+ if (BufferSize % Private->BlockSize != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
+ if (Offset + BufferSize > Private->End) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Since the BlockIO2 call Parent BlockIO2 directly, so here the offset must
+ // be multiple of BlockSize. If the Spec will be updated the DiskIO to support
+ // BlockIO2, this limitation will be removed and call DiskIO here.
+ //
+ Lba = DivU64x32Remainder (Offset, Private->BlockSize, &UnderRun);
+ if (UnderRun != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Because some kinds of partition have different block size from their parent,
+ // in that case it couldn't call parent Block I/O2.
+ //
+ if (Private->BlockSize != Private->ParentBlockIo->Media->BlockSize) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return Private->ParentBlockIo2->WriteBlocksEx (Private->ParentBlockIo2, MediaId, Lba, Token, BufferSize, Buffer);
+}
+
+/**
+ Flush the Block Device.
+
+ If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED
+ is returned and non-blocking I/O is being used, the Event associated with
+ this request will not be signaled.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in,out] Token A pointer to the token associated with the transaction
+
+ @retval EFI_SUCCESS The flush request was queued if Event is not NULL.
+ All outstanding data was written correctly to the
+ device if the Event is NULL.
+ @retval EFI_DEVICE_ERROR The device reported an error while writting back
+ the data.
+ @retval EFI_WRITE_PROTECTED The device cannot be written to.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
+ of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionFlushBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token
+ )
+{
+ PARTITION_PRIVATE_DATA *Private;
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
+
+ //
+ // Because some kinds of partition have different block size from their parent,
+ // in that case it couldn't call parent Block I/O2.
+ //
+ if (Private->BlockSize != Private->ParentBlockIo->Media->BlockSize) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return Private->ParentBlockIo2->FlushBlocksEx (Private->ParentBlockIo2, Token);
+}
/**
Create a child handle for a logical block device that represents the
bytes Start to End of the Parent Block IO device.
- @param[in] This Protocol instance pointer
- @param[in] ParentHandle Parent Handle for new child
- @param[in] ParentDiskIo Parent DiskIo interface
- @param[in] ParentBlockIo Parent BlockIo interface
- @param[in] ParentDevicePath Parent Device Path
- @param[in] DevicePathNode Child Device Path node
- @param[in] Start Start Block
- @param[in] End End Block
- @param[in] BlockSize Child block size
- @param[in] InstallEspGuid Flag to install EFI System Partition GUID on handle
-
- @retval EFI_SUCCESS A child handle was added
- @retval other A child handle was not added
+ @param[in] This Protocol instance pointer.
+ @param[in] ParentHandle Parent Handle for new child.
+ @param[in] ParentDiskIo Parent DiskIo interface.
+ @param[in] ParentBlockIo Parent BlockIo interface.
+ @param[in] ParentBlockIo2 Parent BlockIo2 interface.
+ @param[in] ParentDevicePath Parent Device Path.
+ @param[in] DevicePathNode Child Device Path node.
+ @param[in] Start Start Block.
+ @param[in] End End Block.
+ @param[in] BlockSize Child block size.
+ @param[in] InstallEspGuid Flag to install EFI System Partition GUID on handle.
+
+ @retval EFI_SUCCESS A child handle was added.
+ @retval other A child handle was not added.
**/
EFI_STATUS
@@ -649,6 +980,7 @@ PartitionInstallChildHandle (
IN EFI_HANDLE ParentHandle,
IN EFI_DISK_IO_PROTOCOL *ParentDiskIo,
IN EFI_BLOCK_IO_PROTOCOL *ParentBlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *ParentBlockIo2,
IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode,
IN EFI_LBA Start,
@@ -660,6 +992,7 @@ PartitionInstallChildHandle (
EFI_STATUS Status;
PARTITION_PRIVATE_DATA *Private;
+ Status = EFI_SUCCESS;
Private = AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA));
if (Private == NULL) {
return EFI_OUT_OF_RESOURCES;
@@ -672,29 +1005,52 @@ PartitionInstallChildHandle (
Private->BlockSize = BlockSize;
Private->ParentBlockIo = ParentBlockIo;
+ Private->ParentBlockIo2 = ParentBlockIo2;
Private->DiskIo = ParentDiskIo;
- Private->BlockIo.Revision = ParentBlockIo->Revision;
+ if (Private->ParentBlockIo != NULL) {
+ Private->BlockIo.Revision = ParentBlockIo->Revision;
- Private->BlockIo.Media = &Private->Media;
- CopyMem (Private->BlockIo.Media, ParentBlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA));
- Private->Media.LogicalPartition = TRUE;
+ Private->BlockIo.Media = &Private->Media;
+ CopyMem (Private->BlockIo.Media, ParentBlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA));
+
+
+ Private->BlockIo.Reset = PartitionReset;
+ Private->BlockIo.ReadBlocks = PartitionReadBlocks;
+ Private->BlockIo.WriteBlocks = PartitionWriteBlocks;
+ Private->BlockIo.FlushBlocks = PartitionFlushBlocks;
+ }
+
+ if (Private->ParentBlockIo2 != NULL) {
+ Private->BlockIo2.Media = &Private->Media2;
+ CopyMem (Private->BlockIo2.Media, ParentBlockIo2->Media, sizeof (EFI_BLOCK_IO_MEDIA));
+
+ Private->BlockIo2.Reset = PartitionResetEx;
+ Private->BlockIo2.ReadBlocksEx = PartitionReadBlocksEx;
+ Private->BlockIo2.WriteBlocksEx = PartitionWriteBlocksEx;
+ Private->BlockIo2.FlushBlocksEx = PartitionFlushBlocksEx;
+ }
- //
- // Logical BlockIo instance doesn't have IoAlign restriction because it implements block io operation based on DiskIo
- //
Private->Media.IoAlign = 0;
+ Private->Media.LogicalPartition = TRUE;
Private->Media.LastBlock = DivU64x32 (
MultU64x32 (
End - Start + 1,
- ParentBlockIo->Media->BlockSize
+ (ParentBlockIo != NULL) ? ParentBlockIo->Media->BlockSize : ParentBlockIo2->Media->BlockSize
),
- BlockSize
+ BlockSize
) - 1;
Private->Media.BlockSize = (UINT32) BlockSize;
//
+ // For BlockIO2, it should keep the same alignment with the parent BlockIO2's.
+ //
+ Private->Media2.LogicalPartition = TRUE;
+ Private->Media2.LastBlock = Private->Media.LastBlock;
+ Private->Media2.BlockSize = (UINT32) BlockSize;
+
+ //
// Per UEFI Spec, LowestAlignedLba and LogicalBlocksPerPhysicalBlock must be 0
// for logical partitions.
//
@@ -703,12 +1059,7 @@ PartitionInstallChildHandle (
Private->BlockIo.Media->LogicalBlocksPerPhysicalBlock = 0;
}
- Private->BlockIo.Reset = PartitionReset;
- Private->BlockIo.ReadBlocks = PartitionReadBlocks;
- Private->BlockIo.WriteBlocks = PartitionWriteBlocks;
- Private->BlockIo.FlushBlocks = PartitionFlushBlocks;
-
- Private->DevicePath = AppendDevicePathNode (ParentDevicePath, DevicePathNode);
+ Private->DevicePath = AppendDevicePathNode (ParentDevicePath, DevicePathNode);
if (Private->DevicePath == NULL) {
FreePool (Private);
@@ -723,20 +1074,61 @@ PartitionInstallChildHandle (
//
Private->EspGuid = NULL;
}
+
//
- // Create the new handle
+ // Create the new handle.
+ // BlockIO2 will be installed on the condition that the blocksize of parent BlockIO
+ // is same with the child BlockIO's. Instead of calling the DiskIO, the child BlockIO2
+ // directly call the parent BlockIO and doesn't handle the different block size issue.
+ // If SPEC will update the DiskIO to support the Non-Blocking model, the BlockIO2 will call
+ // DiskIO to handle the blocksize unequal issue and the limitation will be remove from
+ // here.
//
Private->Handle = NULL;
- Status = gBS->InstallMultipleProtocolInterfaces (
- &Private->Handle,
- &gEfiDevicePathProtocolGuid,
- Private->DevicePath,
- &gEfiBlockIoProtocolGuid,
- &Private->BlockIo,
- Private->EspGuid,
- NULL,
- NULL
- );
+ if ((Private->ParentBlockIo != NULL) &&
+ (Private->ParentBlockIo2 != NULL) &&
+ (Private->ParentBlockIo2->Media->BlockSize == BlockSize)
+ ) {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Private->Handle,
+ &gEfiDevicePathProtocolGuid,
+ Private->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &Private->BlockIo,
+ &gEfiBlockIo2ProtocolGuid,
+ &Private->BlockIo2,
+ Private->EspGuid,
+ NULL,
+ NULL
+ );
+ } else {
+ if (Private->ParentBlockIo != NULL) {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Private->Handle,
+ &gEfiDevicePathProtocolGuid,
+ Private->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &Private->BlockIo,
+ Private->EspGuid,
+ NULL,
+ NULL
+ );
+ }
+ if (Private->ParentBlockIo2 != NULL &&
+ Private->ParentBlockIo2->Media->BlockSize == BlockSize
+ ) {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Private->Handle,
+ &gEfiDevicePathProtocolGuid,
+ Private->DevicePath,
+ &gEfiBlockIo2ProtocolGuid,
+ &Private->BlockIo2,
+ Private->EspGuid,
+ NULL,
+ NULL
+ );
+ }
+ }
if (!EFI_ERROR (Status)) {
//