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); +} +