X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=MdeModulePkg%2FUniversal%2FDisk%2FPartitionDxe%2FPartition.c;h=d1c878ad2e7ab3e35b2cbabf76fa5e52ae6f8395;hp=28639b0117c6899f527b88f04604f5c0d6462b72;hb=9d510e61fceee7b92955ef9a3c20343752d8ce3f;hpb=69c0fbd2c51739ea0fb4b9b4a4796b674e6d1d6e
diff --git a/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c b/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c
index 28639b0117..d1c878ad2e 100644
--- a/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c
+++ b/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c
@@ -1,17 +1,12 @@
/** @file
Partition driver that produces logical BlockIo devices from a physical
BlockIo device. The logical BlockIo devices are based on the format
- of the raw block devices media. Currently "El Torito CD-ROM", Legacy
+ of the raw block devices media. Currently "El Torito CD-ROM", UDF, Legacy
MBR, and GPT partition schemes are supported.
-Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.
-This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution. The full text of the license may be found at
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -26,8 +21,8 @@ EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding = {
PartitionDriverBindingStart,
PartitionDriverBindingStop,
//
- // Grub4Dos copies the BPB of the first partition to the MBR. If the
- // DriverBindingStart() of the Fat driver gets run before that of Partition
+ // Grub4Dos copies the BPB of the first partition to the MBR. If the
+ // DriverBindingStart() of the Fat driver gets run before that of Partition
// driver only the first partition can be recognized.
// Let the driver binding version of Partition driver be higher than that of
// Fat driver to make sure the DriverBindingStart() of the Partition driver
@@ -39,12 +34,12 @@ EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding = {
};
//
-// Prioritized function list to detect partition table.
+// Prioritized function list to detect partition table.
//
PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable[] = {
PartitionInstallGptChildHandles,
- PartitionInstallElToritoChildHandles,
PartitionInstallMbrChildHandles,
+ PartitionInstallUdfChildHandles,
NULL
};
@@ -81,7 +76,7 @@ PartitionDriverBindingSupported (
//
if (RemainingDevicePath != NULL) {
//
- // Check if RemainingDevicePath is the End of Device Path Node,
+ // Check if RemainingDevicePath is the End of Device Path Node,
// if yes, go on checking other conditions
//
if (!IsDevicePathEnd (RemainingDevicePath)) {
@@ -204,13 +199,13 @@ PartitionDriverBindingStart (
EFI_TPL OldTpl;
BlockIo2 = NULL;
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
//
// Check RemainingDevicePath validation
//
if (RemainingDevicePath != NULL) {
//
- // Check if RemainingDevicePath is the End of Device Path Node,
+ // Check if RemainingDevicePath is the End of Device Path Node,
// if yes, return EFI_SUCCESS
//
if (IsDevicePathEnd (RemainingDevicePath)) {
@@ -305,9 +300,9 @@ PartitionDriverBindingStart (
if (BlockIo->Media->MediaPresent ||
(BlockIo->Media->RemovableMedia && !BlockIo->Media->LogicalPartition)) {
//
- // Try for GPT, then El Torito, and then legacy MBR partition types. If the
- // media supports a given partition type install child handles to represent
- // the partitions described by the media.
+ // Try for GPT, then legacy MBR partition types, and then UDF and El Torito.
+ // If the media supports a given partition type install child handles to
+ // represent the partitions described by the media.
//
Routine = &mPartitionDetectRoutineTable[0];
while (*Routine != NULL) {
@@ -332,12 +327,12 @@ PartitionDriverBindingStart (
// driver. So don't try to close them. Otherwise, we will break the dependency
// between the controller and the driver set up before.
//
- // In the case that when the media changes on a device it will Reinstall the
+ // In the case that when the media changes on a device it will Reinstall the
// BlockIo interaface. This will cause a call to our Stop(), and a subsequent
// reentrant call to our Start() successfully. We should leave the device open
// when this happen. The "media change" case includes either the status is
- // EFI_MEDIA_CHANGED or it is a "media" to "no media" change.
- //
+ // EFI_MEDIA_CHANGED or it is a "media" to "no media" change.
+ //
if (EFI_ERROR (Status) &&
!EFI_ERROR (OpenStatus) &&
Status != EFI_MEDIA_CHANGED &&
@@ -350,7 +345,7 @@ PartitionDriverBindingStart (
);
//
// Close Parent DiskIo2 if has.
- //
+ //
gBS->CloseProtocol (
ControllerHandle,
&gEfiDiskIo2ProtocolGuid,
@@ -401,12 +396,23 @@ PartitionDriverBindingStop (
BOOLEAN AllChildrenStopped;
PARTITION_PRIVATE_DATA *Private;
EFI_DISK_IO_PROTOCOL *DiskIo;
+ EFI_GUID *TypeGuid;
BlockIo = NULL;
BlockIo2 = NULL;
Private = NULL;
if (NumberOfChildren == 0) {
+ //
+ // In the case of re-entry of the PartitionDriverBindingStop, the
+ // NumberOfChildren may not reflect the actual number of children on the
+ // bus driver. Hence, additional check is needed here.
+ //
+ if (HasChildren (ControllerHandle)) {
+ DEBUG((EFI_D_ERROR, "PartitionDriverBindingStop: Still has child.\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
//
// Close the bus driver
//
@@ -418,7 +424,7 @@ PartitionDriverBindingStop (
);
//
// Close Parent BlockIO2 if has.
- //
+ //
gBS->CloseProtocol (
ControllerHandle,
&gEfiDiskIo2ProtocolGuid,
@@ -455,52 +461,86 @@ PartitionDriverBindingStop (
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
+ );
Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo);
+ if (Private->InStop) {
+ //
+ // If the child handle is going to be stopped again during the re-entry
+ // of DriverBindingStop, just do nothing.
+ //
+ break;
+ }
+ Private->InStop = TRUE;
+
+ BlockIo->FlushBlocks (BlockIo);
+
+ if (BlockIo2 != NULL) {
+ Status = BlockIo2->FlushBlocksEx (BlockIo2, NULL);
+ DEBUG((EFI_D_ERROR, "PartitionDriverBindingStop: FlushBlocksEx returned with %r\n", Status));
+ } else {
+ Status = EFI_SUCCESS;
+ }
+
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index]
+ );
+
+ if (IsZeroGuid (&Private->TypeGuid)) {
+ TypeGuid = NULL;
+ } else {
+ TypeGuid = &Private->TypeGuid;
+ }
- 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);
- BlockIo2->FlushBlocksEx (BlockIo2, NULL);
- Status = gBS->UninstallMultipleProtocolInterfaces (
- ChildHandleBuffer[Index],
- &gEfiDevicePathProtocolGuid,
- Private->DevicePath,
- &gEfiBlockIoProtocolGuid,
- &Private->BlockIo,
- &gEfiBlockIo2ProtocolGuid,
- &Private->BlockIo2,
- Private->EspGuid,
- NULL,
- NULL
- );
+ //
+ // Some device drivers might re-install the BlockIO(2) protocols for a
+ // media change condition. Therefore, if the FlushBlocksEx returned with
+ // EFI_MEDIA_CHANGED, just let the BindingStop fail to avoid potential
+ // reference of already stopped child handle.
+ //
+ if (Status != EFI_MEDIA_CHANGED) {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ Private->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &Private->BlockIo,
+ &gEfiBlockIo2ProtocolGuid,
+ &Private->BlockIo2,
+ &gEfiPartitionInfoProtocolGuid,
+ &Private->PartitionInfo,
+ TypeGuid,
+ NULL,
+ NULL
+ );
+ }
} else {
- BlockIo->FlushBlocks (BlockIo);
Status = gBS->UninstallMultipleProtocolInterfaces (
ChildHandleBuffer[Index],
&gEfiDevicePathProtocolGuid,
Private->DevicePath,
&gEfiBlockIoProtocolGuid,
&Private->BlockIo,
- Private->EspGuid,
+ &gEfiPartitionInfoProtocolGuid,
+ &Private->PartitionInfo,
+ TypeGuid,
NULL,
NULL
);
}
if (EFI_ERROR (Status)) {
+ Private->InStop = FALSE;
gBS->OpenProtocol (
ControllerHandle,
&gEfiDiskIoProtocolGuid,
@@ -516,6 +556,9 @@ PartitionDriverBindingStop (
if (EFI_ERROR (Status)) {
AllChildrenStopped = FALSE;
+ if (Status == EFI_MEDIA_CHANGED) {
+ break;
+ }
}
}
@@ -576,11 +619,15 @@ ProbeMediaStatus (
)
{
EFI_STATUS Status;
+ UINT8 Buffer[1];
//
- // Read 1 byte from offset 0 but passing NULL as buffer pointer
+ // Read 1 byte from offset 0 to check if the MediaId is still valid.
+ // The reading operation is synchronious thus it is not worth it to
+ // allocate a buffer from the pool. The destination buffer for the
+ // data is in the stack.
//
- Status = DiskIo->ReadDisk (DiskIo, MediaId, 0, 1, NULL);
+ Status = DiskIo->ReadDisk (DiskIo, MediaId, 0, 1, (VOID*)Buffer);
if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {
return Status;
}
@@ -733,11 +780,15 @@ ProbeMediaStatusEx (
)
{
EFI_STATUS Status;
+ UINT8 Buffer[1];
//
- // Read 1 byte from offset 0 but passing NULL as buffer pointer
+ // Read 1 byte from offset 0 to check if the MediaId is still valid.
+ // The reading operation is synchronious thus it is not worth it to
+ // allocate a buffer from the pool. The destination buffer for the
+ // data is in the stack.
//
- Status = DiskIo2->ReadDiskEx (DiskIo2, MediaId, 0, NULL, 1, NULL);
+ Status = DiskIo2->ReadDiskEx (DiskIo2, MediaId, 0, NULL, 1, (VOID*)Buffer);
if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {
return Status;
}
@@ -836,7 +887,7 @@ PartitionCreateAccessTask (
/**
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
@@ -844,13 +895,13 @@ PartitionCreateAccessTask (
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
+ @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
+ @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
@@ -862,7 +913,7 @@ PartitionCreateAccessTask (
@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,
+ @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.
@@ -937,7 +988,7 @@ PartitionReadBlocksEx (
@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,
+ @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.
@@ -969,7 +1020,7 @@ PartitionWriteBlocksEx (
if (Offset + BufferSize > Private->End) {
return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_INVALID_PARAMETER);
}
-
+
if ((Token != NULL) && (Token->Event != NULL)) {
Task = PartitionCreateAccessTask (Token);
if (Task == NULL) {
@@ -989,10 +1040,10 @@ PartitionWriteBlocksEx (
/**
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.
+ 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
@@ -1052,10 +1103,11 @@ PartitionFlushBlocksEx (
@param[in] ParentBlockIo2 Parent BlockIo2 interface.
@param[in] ParentDevicePath Parent Device Path.
@param[in] DevicePathNode Child Device Path node.
+ @param[in] PartitionInfo Child Partition Information interface.
@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.
+ @param[in] TypeGuid Partition GUID Type.
@retval EFI_SUCCESS A child handle was added.
@retval other A child handle was not added.
@@ -1071,10 +1123,11 @@ PartitionInstallChildHandle (
IN EFI_BLOCK_IO2_PROTOCOL *ParentBlockIo2,
IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode,
+ IN EFI_PARTITION_INFO_PROTOCOL *PartitionInfo,
IN EFI_LBA Start,
IN EFI_LBA End,
IN UINT32 BlockSize,
- IN BOOLEAN InstallEspGuid
+ IN EFI_GUID *TypeGuid
)
{
EFI_STATUS Status;
@@ -1101,7 +1154,7 @@ PartitionInstallChildHandle (
// Set the BlockIO into Private Data.
//
Private->BlockIo.Revision = ParentBlockIo->Revision;
-
+
Private->BlockIo.Media = &Private->Media;
CopyMem (Private->BlockIo.Media, ParentBlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA));
@@ -1121,7 +1174,7 @@ PartitionInstallChildHandle (
Private->BlockIo2.Reset = PartitionResetEx;
Private->BlockIo2.ReadBlocksEx = PartitionReadBlocksEx;
Private->BlockIo2.WriteBlocksEx = PartitionWriteBlocksEx;
- Private->BlockIo2.FlushBlocksEx = PartitionFlushBlocksEx;
+ Private->BlockIo2.FlushBlocksEx = PartitionFlushBlocksEx;
}
Private->Media.IoAlign = 0;
@@ -1163,17 +1216,19 @@ PartitionInstallChildHandle (
return EFI_OUT_OF_RESOURCES;
}
- if (InstallEspGuid) {
- Private->EspGuid = &gEfiPartTypeSystemPartGuid;
+ //
+ // Set the PartitionInfo into Private Data.
+ //
+ CopyMem (&Private->PartitionInfo, PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
+
+ if (TypeGuid != NULL) {
+ CopyGuid(&(Private->TypeGuid), TypeGuid);
} else {
- //
- // If NULL InstallMultipleProtocolInterfaces will ignore it.
- //
- Private->EspGuid = NULL;
+ ZeroMem ((VOID *)&(Private->TypeGuid), sizeof (EFI_GUID));
}
//
- // Create the new handle.
+ // Create the new handle.
//
Private->Handle = NULL;
if (Private->DiskIo2 != NULL) {
@@ -1185,18 +1240,22 @@ PartitionInstallChildHandle (
&Private->BlockIo,
&gEfiBlockIo2ProtocolGuid,
&Private->BlockIo2,
- Private->EspGuid,
+ &gEfiPartitionInfoProtocolGuid,
+ &Private->PartitionInfo,
+ TypeGuid,
NULL,
NULL
);
- } else {
+ } else {
Status = gBS->InstallMultipleProtocolInterfaces (
&Private->Handle,
&gEfiDevicePathProtocolGuid,
Private->DevicePath,
&gEfiBlockIoProtocolGuid,
&Private->BlockIo,
- Private->EspGuid,
+ &gEfiPartitionInfoProtocolGuid,
+ &Private->PartitionInfo,
+ TypeGuid,
NULL,
NULL
);
@@ -1226,9 +1285,9 @@ PartitionInstallChildHandle (
/**
The user Entry Point for module Partition. The user code starts with this function.
- @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
@param[in] SystemTable A pointer to the EFI System Table.
-
+
@retval EFI_SUCCESS The entry point is executed successfully.
@retval other Some error occurs when executing this entry point.
@@ -1259,3 +1318,41 @@ InitializePartition (
return Status;
}
+
+/**
+ Test to see if there is any child on ControllerHandle.
+
+ @param[in] ControllerHandle Handle of device to test.
+
+ @retval TRUE There are children on the ControllerHandle.
+ @retval FALSE No child is on the ControllerHandle.
+
+**/
+BOOLEAN
+HasChildren (
+ IN EFI_HANDLE ControllerHandle
+ )
+{
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
+ UINTN EntryCount;
+ EFI_STATUS Status;
+ UINTN Index;
+
+ Status = gBS->OpenProtocolInformation (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ &OpenInfoBuffer,
+ &EntryCount
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ for (Index = 0; Index < EntryCount; Index++) {
+ if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
+ break;
+ }
+ }
+ FreePool (OpenInfoBuffer);
+
+ return (BOOLEAN) (Index < EntryCount);
+}
+