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