]> 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 b68c1db3e66cd0ffd3230c0cc214e7f562d3a5f5..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 - 2007, Intel Corporation                                              \r
-  All rights reserved. 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
 #include "Partition.h"\r
 \r
 //\r
-// Partition Driver Global Variables\r
+// Partition Driver Global Variables.\r
 //\r
 EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding = {\r
   PartitionDriverBindingSupported,\r
   PartitionDriverBindingStart,\r
   PartitionDriverBindingStop,\r
-  0xa,\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
+  // 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
+  // gets run before that of Fat driver so that all the partitions can be recognized.\r
+  //\r
+  0xb,\r
   NULL,\r
   NULL\r
 };\r
 \r
-STATIC \r
+//\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
-\r
-\r
 /**\r
   Test to see if this driver supports ControllerHandle. Any ControllerHandle\r
-  than contains a BlockIo and DiskIo protocol can be supported.\r
+  than contains a BlockIo and DiskIo protocol or a BlockIo2 protocol can be\r
+  supported.\r
 \r
-  @param  This                Protocol instance pointer.\r
-  @param  ControllerHandle    Handle of device to test\r
-  @param  RemainingDevicePath Optional parameter use to pick a specific child\r
-                              device to start.\r
+  @param[in]  This                Protocol instance pointer.\r
+  @param[in]  ControllerHandle    Handle of device to test.\r
+  @param[in]  RemainingDevicePath Optional parameter use to pick a specific child\r
+                                  device to start.\r
 \r
   @retval EFI_SUCCESS         This driver supports this device\r
   @retval EFI_ALREADY_STARTED This driver is already running on this device\r
@@ -67,22 +71,35 @@ PartitionDriverBindingSupported (
   EFI_DISK_IO_PROTOCOL      *DiskIo;\r
   EFI_DEV_PATH              *Node;\r
 \r
+  //\r
+  // Check RemainingDevicePath validation\r
+  //\r
   if (RemainingDevicePath != NULL) {\r
-    Node = (EFI_DEV_PATH *) RemainingDevicePath;\r
-    if (Node->DevPath.Type != MEDIA_DEVICE_PATH ||\r
+    //\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
+      //\r
+      // If RemainingDevicePath isn't the End of Device Path Node,\r
+      // check its validation\r
+      //\r
+      Node = (EFI_DEV_PATH *) RemainingDevicePath;\r
+      if (Node->DevPath.Type != MEDIA_DEVICE_PATH ||\r
         Node->DevPath.SubType != MEDIA_HARDDRIVE_DP ||\r
-        DevicePathNodeLength (&Node->DevPath) != sizeof (HARDDRIVE_DEVICE_PATH)\r
-        ) {\r
-      return EFI_UNSUPPORTED;\r
+        DevicePathNodeLength (&Node->DevPath) != sizeof (HARDDRIVE_DEVICE_PATH)) {\r
+        return EFI_UNSUPPORTED;\r
+      }\r
     }\r
   }\r
+\r
   //\r
   // Open the IO Abstraction(s) needed to perform the supported test\r
   //\r
   Status = gBS->OpenProtocol (\r
                   ControllerHandle,\r
-                  &gEfiDevicePathProtocolGuid,\r
-                  (VOID **) &ParentDevicePath,\r
+                  &gEfiDiskIoProtocolGuid,\r
+                  (VOID **) &DiskIo,\r
                   This->DriverBindingHandle,\r
                   ControllerHandle,\r
                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
@@ -90,7 +107,6 @@ PartitionDriverBindingSupported (
   if (Status == EFI_ALREADY_STARTED) {\r
     return EFI_SUCCESS;\r
   }\r
-\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
@@ -98,19 +114,19 @@ PartitionDriverBindingSupported (
   // Close the I/O Abstraction(s) used to perform the supported test\r
   //\r
   gBS->CloseProtocol (\r
-        ControllerHandle,\r
-        &gEfiDevicePathProtocolGuid,\r
-        This->DriverBindingHandle,\r
-        ControllerHandle\r
-        );\r
+         ControllerHandle,\r
+         &gEfiDiskIoProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         ControllerHandle\r
+         );\r
 \r
   //\r
-  // Open the IO Abstraction(s) needed to perform the supported test\r
+  // Open the EFI Device Path protocol needed to perform the supported test\r
   //\r
   Status = gBS->OpenProtocol (\r
                   ControllerHandle,\r
-                  &gEfiDiskIoProtocolGuid,\r
-                  (VOID **) &DiskIo,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  (VOID **) &ParentDevicePath,\r
                   This->DriverBindingHandle,\r
                   ControllerHandle,\r
                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
@@ -122,12 +138,13 @@ PartitionDriverBindingSupported (
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
+\r
   //\r
-  // Close the I/O Abstraction(s) used to perform the supported test\r
+  // Close protocol, don't use device path protocol in the Support() function\r
   //\r
   gBS->CloseProtocol (\r
         ControllerHandle,\r
-        &gEfiDiskIoProtocolGuid,\r
+        &gEfiDevicePathProtocolGuid,\r
         This->DriverBindingHandle,\r
         ControllerHandle\r
         );\r
@@ -147,16 +164,15 @@ PartitionDriverBindingSupported (
   return Status;\r
 }\r
 \r
-\r
 /**\r
-  Start this driver on ControllerHandle by opening a Block IO and Disk IO\r
-  protocol, reading Device Path, and creating a child handle with a\r
-  Disk IO and device path protocol.\r
+  Start this driver on ControllerHandle by opening a Block IO or a Block IO2\r
+  or both, and Disk IO protocol, reading Device Path, and creating a child\r
+  handle with a Disk IO and device path protocol.\r
 \r
-  @param  This                 Protocol instance pointer.\r
-  @param  ControllerHandle     Handle of device to bind driver to\r
-  @param  RemainingDevicePath  Optional parameter use to pick a specific child\r
-                               device to start.\r
+  @param[in]  This                 Protocol instance pointer.\r
+  @param[in]  ControllerHandle     Handle of device to bind driver to\r
+  @param[in]  RemainingDevicePath  Optional parameter use to pick a specific child\r
+                                   device to start.\r
 \r
   @retval EFI_SUCCESS          This driver is added to ControllerHandle\r
   @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle\r
@@ -174,10 +190,34 @@ PartitionDriverBindingStart (
   EFI_STATUS                Status;\r
   EFI_STATUS                OpenStatus;\r
   EFI_BLOCK_IO_PROTOCOL     *BlockIo;\r
+  EFI_BLOCK_IO2_PROTOCOL    *BlockIo2;\r
   EFI_DISK_IO_PROTOCOL      *DiskIo;\r
+  EFI_DISK_IO2_PROTOCOL     *DiskIo2;\r
   EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;\r
   PARTITION_DETECT_ROUTINE  *Routine;\r
+  BOOLEAN                   MediaPresent;\r
+  EFI_TPL                   OldTpl;\r
+\r
+  BlockIo2 = NULL;\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
+    // if yes, return EFI_SUCCESS\r
+    //\r
+    if (IsDevicePathEnd (RemainingDevicePath)) {\r
+      Status = EFI_SUCCESS;\r
+      goto Exit;\r
+    }\r
+  }\r
 \r
+  //\r
+  // Try to open BlockIO and BlockIO2. If BlockIO would be opened, continue,\r
+  // otherwise, return error.\r
+  //\r
   Status = gBS->OpenProtocol (\r
                   ControllerHandle,\r
                   &gEfiBlockIoProtocolGuid,\r
@@ -187,10 +227,23 @@ PartitionDriverBindingStart (
                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
                   );\r
   if (EFI_ERROR (Status)) {\r
-    return Status;\r
+    goto Exit;\r
   }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiBlockIo2ProtocolGuid,\r
+                  (VOID **) &BlockIo2,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    BlockIo2 = NULL;\r
+  }\r
+\r
   //\r
-  // Get the Device Path Protocol on ControllerHandle's handle\r
+  // Get the Device Path Protocol on ControllerHandle's handle.\r
   //\r
   Status = gBS->OpenProtocol (\r
                   ControllerHandle,\r
@@ -201,9 +254,12 @@ PartitionDriverBindingStart (
                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
                   );\r
   if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
-    return Status;\r
+    goto Exit;\r
   }\r
 \r
+  //\r
+  // Get the DiskIo and DiskIo2.\r
+  //\r
   Status = gBS->OpenProtocol (\r
                   ControllerHandle,\r
                   &gEfiDiskIoProtocolGuid,\r
@@ -219,20 +275,34 @@ PartitionDriverBindingStart (
           This->DriverBindingHandle,\r
           ControllerHandle\r
           );\r
-    return Status;\r
+    goto Exit;\r
   }\r
 \r
   OpenStatus = Status;\r
 \r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiDiskIo2ProtocolGuid,\r
+                  (VOID **) &DiskIo2,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
+    DiskIo2 = NULL;\r
+  }\r
+\r
   //\r
-  // If no media is present, do nothing here.\r
+  // Try to read blocks when there's media or it is removable physical partition.\r
   //\r
-  Status = EFI_UNSUPPORTED;\r
-  if (BlockIo->Media->MediaPresent) {\r
+  Status       = EFI_UNSUPPORTED;\r
+  MediaPresent = BlockIo->Media->MediaPresent;\r
+  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
@@ -240,10 +310,12 @@ PartitionDriverBindingStart (
                    This,\r
                    ControllerHandle,\r
                    DiskIo,\r
+                   DiskIo2,\r
                    BlockIo,\r
+                   BlockIo2,\r
                    ParentDevicePath\r
                    );\r
-      if (!EFI_ERROR (Status) || Status == EFI_MEDIA_CHANGED) {\r
+      if (!EFI_ERROR (Status) || Status == EFI_MEDIA_CHANGED || Status == EFI_NO_MEDIA) {\r
         break;\r
       }\r
       Routine++;\r
@@ -255,13 +327,31 @@ 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
-  if (EFI_ERROR (Status) && !EFI_ERROR (OpenStatus) && Status != EFI_MEDIA_CHANGED) {\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
+  if (EFI_ERROR (Status)          &&\r
+      !EFI_ERROR (OpenStatus)     &&\r
+      Status != EFI_MEDIA_CHANGED &&\r
+      !(MediaPresent && Status == EFI_NO_MEDIA)) {\r
     gBS->CloseProtocol (\r
           ControllerHandle,\r
           &gEfiDiskIoProtocolGuid,\r
           This->DriverBindingHandle,\r
           ControllerHandle\r
           );\r
+    //\r
+    // Close Parent DiskIo2 if has.\r
+    //\r
+    gBS->CloseProtocol (\r
+           ControllerHandle,\r
+           &gEfiDiskIo2ProtocolGuid,\r
+           This->DriverBindingHandle,\r
+           ControllerHandle\r
+           );\r
 \r
     gBS->CloseProtocol (\r
           ControllerHandle,\r
@@ -271,12 +361,13 @@ PartitionDriverBindingStart (
           );\r
   }\r
 \r
+Exit:\r
+  gBS->RestoreTPL (OldTpl);\r
   return Status;\r
 }\r
 \r
-\r
 /**\r
-  Stop this driver on ControllerHandle. Support stoping any child handles\r
+  Stop this driver on ControllerHandle. Support stopping any child handles\r
   created by this driver.\r
 \r
   @param  This              Protocol instance pointer.\r
@@ -301,11 +392,27 @@ PartitionDriverBindingStop (
   EFI_STATUS              Status;\r
   UINTN                   Index;\r
   EFI_BLOCK_IO_PROTOCOL   *BlockIo;\r
+  EFI_BLOCK_IO2_PROTOCOL  *BlockIo2;\r
   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
@@ -315,6 +422,15 @@ PartitionDriverBindingStop (
           This->DriverBindingHandle,\r
           ControllerHandle\r
           );\r
+    //\r
+    // Close Parent BlockIO2 if has.\r
+    //\r
+    gBS->CloseProtocol (\r
+           ControllerHandle,\r
+           &gEfiDiskIo2ProtocolGuid,\r
+           This->DriverBindingHandle,\r
+           ControllerHandle\r
+           );\r
 \r
     gBS->CloseProtocol (\r
           ControllerHandle,\r
@@ -322,64 +438,127 @@ PartitionDriverBindingStop (
           This->DriverBindingHandle,\r
           ControllerHandle\r
           );\r
-\r
     return EFI_SUCCESS;\r
   }\r
 \r
   AllChildrenStopped = TRUE;\r
   for (Index = 0; Index < NumberOfChildren; Index++) {\r
-    Status = gBS->OpenProtocol (\r
-                    ChildHandleBuffer[Index],\r
-                    &gEfiBlockIoProtocolGuid,\r
-                    (VOID **) &BlockIo,\r
-                    This->DriverBindingHandle,\r
-                    ControllerHandle,\r
-                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
-                    );\r
-    if (!EFI_ERROR (Status)) {\r
-\r
-      Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo);\r
-\r
+    gBS->OpenProtocol (\r
+           ChildHandleBuffer[Index],\r
+           &gEfiBlockIoProtocolGuid,\r
+           (VOID **) &BlockIo,\r
+           This->DriverBindingHandle,\r
+           ControllerHandle,\r
+           EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+           );\r
+    //\r
+    // Try to locate BlockIo2.\r
+    //\r
+    gBS->OpenProtocol (\r
+           ChildHandleBuffer[Index],\r
+           &gEfiBlockIo2ProtocolGuid,\r
+           (VOID **) &BlockIo2,\r
+           This->DriverBindingHandle,\r
+           ControllerHandle,\r
+           EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+           );\r
+\r
+\r
+    Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo);\r
+    if (Private->InStop) {\r
       //\r
-      // All Software protocols have be freed from the handle so remove it.\r
+      // If the child handle is going to be stopped again during the re-entry\r
+      // of DriverBindingStop, just do nothing.\r
       //\r
-      BlockIo->FlushBlocks (BlockIo);\r
+      break;\r
+    }\r
+    Private->InStop = TRUE;\r
 \r
-      Status = gBS->CloseProtocol (\r
-                      ControllerHandle,\r
-                      &gEfiDiskIoProtocolGuid,\r
-                      This->DriverBindingHandle,\r
-                      ChildHandleBuffer[Index]\r
-                      );\r
+    BlockIo->FlushBlocks (BlockIo);\r
 \r
-      Status = gBS->UninstallMultipleProtocolInterfaces (\r
-                      ChildHandleBuffer[Index],\r
-                      &gEfiDevicePathProtocolGuid,\r
-                      Private->DevicePath,\r
-                      &gEfiBlockIoProtocolGuid,\r
-                      &Private->BlockIo,\r
-                      Private->EspGuid,\r
-                      NULL,\r
-                      NULL\r
-                      );\r
-      if (EFI_ERROR (Status)) {\r
-        gBS->OpenProtocol (\r
-              ControllerHandle,\r
-              &gEfiDiskIoProtocolGuid,\r
-              (VOID **) &DiskIo,\r
-              This->DriverBindingHandle,\r
-              ChildHandleBuffer[Index],\r
-              EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
-              );\r
-      } else {\r
-        FreePool (Private->DevicePath);\r
-        FreePool (Private);\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
+    //\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
+      //\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
+      Status = gBS->UninstallMultipleProtocolInterfaces (\r
+                       ChildHandleBuffer[Index],\r
+                       &gEfiDevicePathProtocolGuid,\r
+                       Private->DevicePath,\r
+                       &gEfiBlockIoProtocolGuid,\r
+                       &Private->BlockIo,\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
+             (VOID **) &DiskIo,\r
+             This->DriverBindingHandle,\r
+             ChildHandleBuffer[Index],\r
+             EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+             );\r
+    } else {\r
+      FreePool (Private->DevicePath);\r
+      FreePool (Private);\r
     }\r
 \r
     if (EFI_ERROR (Status)) {\r
       AllChildrenStopped = FALSE;\r
+      if (Status == EFI_MEDIA_CHANGED) {\r
+        break;\r
+      }\r
     }\r
   }\r
 \r
@@ -402,7 +581,6 @@ PartitionDriverBindingStop (
                                not be reset.\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
 EFIAPI\r
 PartitionReset (\r
@@ -420,6 +598,41 @@ PartitionReset (
                                   );\r
 }\r
 \r
+/**\r
+  Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED\r
+  for no media or media change case. Otherwise DefaultStatus is returned.\r
+\r
+  @param DiskIo             Pointer to the DiskIo instance.\r
+  @param MediaId            Id of the media, changes every time the media is replaced.\r
+  @param DefaultStatus      The default status to return when it's not the no media\r
+                            or media change case.\r
+\r
+  @retval EFI_NO_MEDIA      There is no media.\r
+  @retval EFI_MEDIA_CHANGED The media was changed.\r
+  @retval others            The default status to return.\r
+**/\r
+EFI_STATUS\r
+ProbeMediaStatus (\r
+  IN EFI_DISK_IO_PROTOCOL    *DiskIo,\r
+  IN UINT32                  MediaId,\r
+  IN EFI_STATUS              DefaultStatus\r
+  )\r
+{\r
+  EFI_STATUS                 Status;\r
+  UINT8                      Buffer[1];\r
+\r
+  //\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, (VOID*)Buffer);\r
+  if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {\r
+    return Status;\r
+  }\r
+  return DefaultStatus;\r
+}\r
 \r
 /**\r
   Read by using the Disk IO protocol on the parent device. Lba addresses\r
@@ -440,7 +653,6 @@ PartitionReset (
                                 valid for the device.\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
 EFIAPI\r
 PartitionReadBlocks (\r
@@ -457,12 +669,12 @@ PartitionReadBlocks (
   Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);\r
 \r
   if (BufferSize % Private->BlockSize != 0) {\r
-    return EFI_BAD_BUFFER_SIZE;\r
+    return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE);\r
   }\r
 \r
   Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;\r
   if (Offset + BufferSize > Private->End) {\r
-    return EFI_INVALID_PARAMETER;\r
+    return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER);\r
   }\r
   //\r
   // Because some kinds of partition have different block size from their parent\r
@@ -476,11 +688,11 @@ PartitionReadBlocks (
   Write by using the Disk IO protocol on the parent device. Lba addresses\r
   must be converted to byte offsets.\r
 \r
-  @param  This       Protocol instance pointer.\r
-  @param  MediaId    Id of the media, changes every time the media is replaced.\r
-  @param  Lba        The starting Logical Block Address to read from\r
-  @param  BufferSize Size of Buffer, must be a multiple of device block size.\r
-  @param  Buffer     Buffer containing read data\r
+  @param[in]  This       Protocol instance pointer.\r
+  @param[in]  MediaId    Id of the media, changes every time the media is replaced.\r
+  @param[in]  Lba        The starting Logical Block Address to read from\r
+  @param[in]  BufferSize Size of Buffer, must be a multiple of device block size.\r
+  @param[in]  Buffer     Buffer containing data to be written to device.\r
 \r
   @retval EFI_SUCCESS           The data was written correctly to the device.\r
   @retval EFI_WRITE_PROTECTED   The device can not be written to.\r
@@ -492,7 +704,6 @@ PartitionReadBlocks (
                                 valid for the device.\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
 EFIAPI\r
 PartitionWriteBlocks (\r
@@ -500,7 +711,7 @@ PartitionWriteBlocks (
   IN UINT32                 MediaId,\r
   IN EFI_LBA                Lba,\r
   IN UINTN                  BufferSize,\r
-  OUT VOID                  *Buffer\r
+  IN VOID                  *Buffer\r
   )\r
 {\r
   PARTITION_PRIVATE_DATA  *Private;\r
@@ -509,12 +720,12 @@ PartitionWriteBlocks (
   Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);\r
 \r
   if (BufferSize % Private->BlockSize != 0) {\r
-    return EFI_BAD_BUFFER_SIZE;\r
+    return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE);\r
   }\r
 \r
   Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;\r
   if (Offset + BufferSize > Private->End) {\r
-    return EFI_INVALID_PARAMETER;\r
+    return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER);\r
   }\r
   //\r
   // Because some kinds of partition have different block size from their parent\r
@@ -535,7 +746,6 @@ PartitionWriteBlocks (
   @retval EFI_NO_MEDIA      There is no media in the device.\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
 EFIAPI\r
 PartitionFlushBlocks (\r
@@ -549,6 +759,336 @@ PartitionFlushBlocks (
   return Private->ParentBlockIo->FlushBlocks (Private->ParentBlockIo);\r
 }\r
 \r
+/**\r
+  Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED\r
+  for no media or media change case. Otherwise DefaultStatus is returned.\r
+\r
+  @param DiskIo2            Pointer to the DiskIo2 instance.\r
+  @param MediaId            Id of the media, changes every time the media is replaced.\r
+  @param DefaultStatus      The default status to return when it's not the no media\r
+                            or media change case.\r
+\r
+  @retval EFI_NO_MEDIA      There is no media.\r
+  @retval EFI_MEDIA_CHANGED The media was changed.\r
+  @retval others            The default status to return.\r
+**/\r
+EFI_STATUS\r
+ProbeMediaStatusEx (\r
+  IN EFI_DISK_IO2_PROTOCOL   *DiskIo2,\r
+  IN UINT32                  MediaId,\r
+  IN EFI_STATUS              DefaultStatus\r
+  )\r
+{\r
+  EFI_STATUS                 Status;\r
+  UINT8                      Buffer[1];\r
+\r
+  //\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, (VOID*)Buffer);\r
+  if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {\r
+    return Status;\r
+  }\r
+  return DefaultStatus;\r
+}\r
+\r
+/**\r
+  Reset the Block Device throught Block I/O2 protocol.\r
+\r
+  @param  This                 Protocol instance pointer.\r
+  @param  ExtendedVerification Driver may perform diagnostics on reset.\r
+\r
+  @retval EFI_SUCCESS          The device was reset.\r
+  @retval EFI_DEVICE_ERROR     The device is not functioning properly and could\r
+                               not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PartitionResetEx (\r
+  IN EFI_BLOCK_IO2_PROTOCOL *This,\r
+  IN BOOLEAN                ExtendedVerification\r
+  )\r
+{\r
+  PARTITION_PRIVATE_DATA  *Private;\r
+\r
+  Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);\r
+\r
+  return Private->ParentBlockIo2->Reset (\r
+                                    Private->ParentBlockIo2,\r
+                                    ExtendedVerification\r
+                                    );\r
+}\r
+\r
+/**\r
+  The general callback for the DiskIo2 interfaces.\r
+  @param  Event                 Event whose notification function is being invoked.\r
+  @param  Context               The pointer to the notification function's context,\r
+                                which points to the PARTITION_ACCESS_TASK instance.\r
+**/\r
+VOID\r
+EFIAPI\r
+PartitionOnAccessComplete (\r
+  IN EFI_EVENT                 Event,\r
+  IN VOID                      *Context\r
+  )\r
+{\r
+  PARTITION_ACCESS_TASK   *Task;\r
+\r
+  Task = (PARTITION_ACCESS_TASK *) Context;\r
+\r
+  gBS->CloseEvent (Event);\r
+\r
+  Task->BlockIo2Token->TransactionStatus = Task->DiskIo2Token.TransactionStatus;\r
+  gBS->SignalEvent (Task->BlockIo2Token->Event);\r
+\r
+  FreePool (Task);\r
+}\r
+\r
+/**\r
+  Create a new PARTITION_ACCESS_TASK instance.\r
+\r
+  @param  Token  Pointer to the EFI_BLOCK_IO2_TOKEN.\r
+\r
+  @return Pointer to the created PARTITION_ACCESS_TASK instance or NULL upon failure.\r
+**/\r
+PARTITION_ACCESS_TASK *\r
+PartitionCreateAccessTask (\r
+  IN EFI_BLOCK_IO2_TOKEN    *Token\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  PARTITION_ACCESS_TASK     *Task;\r
+\r
+  Task = AllocatePool (sizeof (*Task));\r
+  if (Task == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  PartitionOnAccessComplete,\r
+                  Task,\r
+                  &Task->DiskIo2Token.Event\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (Task);\r
+    return NULL;\r
+  }\r
+\r
+  Task->BlockIo2Token = Token;\r
+\r
+  return Task;\r
+}\r
+\r
+/**\r
+  Read BufferSize bytes from Lba into Buffer.\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
+  non-blocking I/O is being used, the Event associated with this request will\r
+  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
+                              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
+                              explicit ownership of the buffer.\r
+\r
+  @retval EFI_SUCCESS           The read request was queued if Token->Event is\r
+                                not NULL.The data was read correctly from the\r
+                                device if the Token->Event is NULL.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing\r
+                                the read.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @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
+                                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
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PartitionReadBlocksEx (\r
+  IN     EFI_BLOCK_IO2_PROTOCOL *This,\r
+  IN     UINT32                 MediaId,\r
+  IN     EFI_LBA                Lba,\r
+  IN OUT EFI_BLOCK_IO2_TOKEN    *Token,\r
+  IN     UINTN                  BufferSize,\r
+  OUT    VOID                   *Buffer\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  PARTITION_PRIVATE_DATA  *Private;\r
+  UINT64                  Offset;\r
+  PARTITION_ACCESS_TASK   *Task;\r
+\r
+  Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);\r
+\r
+  if (BufferSize % Private->BlockSize != 0) {\r
+    return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_BAD_BUFFER_SIZE);\r
+  }\r
+\r
+  Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;\r
+  if (Offset + BufferSize > Private->End) {\r
+    return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_INVALID_PARAMETER);\r
+  }\r
+\r
+  if ((Token != NULL) && (Token->Event != NULL)) {\r
+    Task = PartitionCreateAccessTask (Token);\r
+    if (Task == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    Status = Private->DiskIo2->ReadDiskEx (Private->DiskIo2, MediaId, Offset, &Task->DiskIo2Token, BufferSize, Buffer);\r
+    if (EFI_ERROR (Status)) {\r
+      gBS->CloseEvent (Task->DiskIo2Token.Event);\r
+      FreePool (Task);\r
+    }\r
+  } else {\r
+    Status = Private->DiskIo2->ReadDiskEx (Private->DiskIo2, MediaId, Offset, NULL, BufferSize, Buffer);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Write BufferSize bytes from Lba into Buffer.\r
+\r
+  This function writes the requested number of blocks to the device. All blocks\r
+  are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,\r
+  EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is\r
+  being used, the Event associated with this request will not be signaled.\r
+\r
+  @param[in]       This       Indicates a pointer to the calling context.\r
+  @param[in]       MediaId    The media ID that the write request is for.\r
+  @param[in]       Lba        The starting logical block address to be written. The\r
+                              caller is responsible for writing to only legitimate\r
+                              locations.\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[in]       Buffer     A pointer to the source buffer for the data.\r
+\r
+  @retval EFI_SUCCESS           The write request was queued if Event is not NULL.\r
+                                The data was written correctly to the device if\r
+                                the Event is NULL.\r
+  @retval EFI_WRITE_PROTECTED   The device can not be written to.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @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
+                                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
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PartitionWriteBlocksEx (\r
+  IN     EFI_BLOCK_IO2_PROTOCOL *This,\r
+  IN     UINT32                 MediaId,\r
+  IN     EFI_LBA                Lba,\r
+  IN OUT EFI_BLOCK_IO2_TOKEN    *Token,\r
+  IN     UINTN                  BufferSize,\r
+  IN     VOID                   *Buffer\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  PARTITION_PRIVATE_DATA  *Private;\r
+  UINT64                  Offset;\r
+  PARTITION_ACCESS_TASK   *Task;\r
+\r
+  Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);\r
+\r
+  if (BufferSize % Private->BlockSize != 0) {\r
+    return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_BAD_BUFFER_SIZE);\r
+  }\r
+\r
+  Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;\r
+  if (Offset + BufferSize > Private->End) {\r
+    return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_INVALID_PARAMETER);\r
+  }\r
+\r
+  if ((Token != NULL) && (Token->Event != NULL)) {\r
+    Task = PartitionCreateAccessTask (Token);\r
+    if (Task == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    Status =  Private->DiskIo2->WriteDiskEx (Private->DiskIo2, MediaId, Offset, &Task->DiskIo2Token, BufferSize, Buffer);\r
+    if (EFI_ERROR (Status)) {\r
+      gBS->CloseEvent (Task->DiskIo2Token.Event);\r
+      FreePool (Task);\r
+    }\r
+  } else {\r
+    Status = Private->DiskIo2->WriteDiskEx (Private->DiskIo2, MediaId, Offset, NULL, BufferSize, Buffer);\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Flush the Block Device.\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
+\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
+\r
+  @retval EFI_SUCCESS          The flush request was queued if Event is not NULL.\r
+                               All outstanding data was written correctly to the\r
+                               device if the Event is NULL.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error while writting back\r
+                               the data.\r
+  @retval EFI_WRITE_PROTECTED  The device cannot be written to.\r
+  @retval EFI_NO_MEDIA         There is no media in the device.\r
+  @retval EFI_MEDIA_CHANGED    The MediaId is not for the current media.\r
+  @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
+                               of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PartitionFlushBlocksEx (\r
+  IN     EFI_BLOCK_IO2_PROTOCOL *This,\r
+  IN OUT EFI_BLOCK_IO2_TOKEN    *Token\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  PARTITION_PRIVATE_DATA  *Private;\r
+  PARTITION_ACCESS_TASK   *Task;\r
+\r
+  Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);\r
+\r
+  if ((Token != NULL) && (Token->Event != NULL)) {\r
+    Task = PartitionCreateAccessTask (Token);\r
+    if (Task == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    Status = Private->DiskIo2->FlushDiskEx (Private->DiskIo2, &Task->DiskIo2Token);\r
+    if (EFI_ERROR (Status)) {\r
+      gBS->CloseEvent (Task->DiskIo2Token.Event);\r
+      FreePool (Task);\r
+    }\r
+  } else {\r
+    Status = Private->DiskIo2->FlushDiskEx (Private->DiskIo2, NULL);\r
+  }\r
+  return Status;\r
+}\r
 \r
 \r
 /**\r
@@ -556,19 +1096,21 @@ PartitionFlushBlocks (
   bytes Start to End of the Parent Block IO device.\r
 \r
   @param[in]  This              Protocol instance pointer.\r
-  @param[in]  This              Calling context.\r
-  @param[in]  ParentHandle      Parent Handle for new child\r
-  @param[in]  ParentDiskIo      Parent DiskIo interface\r
-  @param[in]  ParentBlockIo     Parent BlockIo interface\r
-  @param[in]  ParentDevicePath  Parent Device Path\r
-  @param[in]  DevicePathNode    Child Device Path node\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
-\r
-  @retval EFI_SUCCESS       A child handle was added\r
-  @retval other             A child handle was not added\r
+  @param[in]  ParentHandle      Parent Handle for new child.\r
+  @param[in]  ParentDiskIo      Parent DiskIo interface.\r
+  @param[in]  ParentDiskIo2     Parent DiskIo2 interface.\r
+  @param[in]  ParentBlockIo     Parent BlockIo interface.\r
+  @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]  TypeGuid          Partition GUID Type.\r
+\r
+  @retval EFI_SUCCESS       A child handle was added.\r
+  @retval other             A child handle was not added.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -576,18 +1118,22 @@ PartitionInstallChildHandle (
   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
   IN  EFI_HANDLE                   ParentHandle,\r
   IN  EFI_DISK_IO_PROTOCOL         *ParentDiskIo,\r
+  IN  EFI_DISK_IO2_PROTOCOL        *ParentDiskIo2,\r
   IN  EFI_BLOCK_IO_PROTOCOL        *ParentBlockIo,\r
+  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
   PARTITION_PRIVATE_DATA  *Private;\r
 \r
+  Status  = EFI_SUCCESS;\r
   Private = AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA));\r
   if (Private == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
@@ -600,57 +1146,120 @@ PartitionInstallChildHandle (
 \r
   Private->BlockSize        = BlockSize;\r
   Private->ParentBlockIo    = ParentBlockIo;\r
+  Private->ParentBlockIo2   = ParentBlockIo2;\r
   Private->DiskIo           = ParentDiskIo;\r
+  Private->DiskIo2          = ParentDiskIo2;\r
 \r
-  Private->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;\r
+  //\r
+  // Set the BlockIO into Private Data.\r
+  //\r
+  Private->BlockIo.Revision = ParentBlockIo->Revision;\r
 \r
   Private->BlockIo.Media    = &Private->Media;\r
   CopyMem (Private->BlockIo.Media, ParentBlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA));\r
+\r
+  Private->BlockIo.Reset        = PartitionReset;\r
+  Private->BlockIo.ReadBlocks   = PartitionReadBlocks;\r
+  Private->BlockIo.WriteBlocks  = PartitionWriteBlocks;\r
+  Private->BlockIo.FlushBlocks  = PartitionFlushBlocks;\r
+\r
+  //\r
+  // Set the BlockIO2 into Private Data.\r
+  //\r
+  if (Private->DiskIo2 != NULL) {\r
+    ASSERT (Private->ParentBlockIo2 != NULL);\r
+    Private->BlockIo2.Media    = &Private->Media2;\r
+    CopyMem (Private->BlockIo2.Media, ParentBlockIo2->Media, sizeof (EFI_BLOCK_IO_MEDIA));\r
+\r
+    Private->BlockIo2.Reset          = PartitionResetEx;\r
+    Private->BlockIo2.ReadBlocksEx   = PartitionReadBlocksEx;\r
+    Private->BlockIo2.WriteBlocksEx  = PartitionWriteBlocksEx;\r
+    Private->BlockIo2.FlushBlocksEx  = PartitionFlushBlocksEx;\r
+  }\r
+\r
+  Private->Media.IoAlign   = 0;\r
   Private->Media.LogicalPartition = TRUE;\r
   Private->Media.LastBlock = DivU64x32 (\r
                                MultU64x32 (\r
                                  End - Start + 1,\r
                                  ParentBlockIo->Media->BlockSize\r
                                  ),\r
-                               BlockSize\r
+                                BlockSize\r
                                ) - 1;\r
 \r
-  Private->Media.BlockSize      = (UINT32) BlockSize;\r
+  Private->Media.BlockSize = (UINT32) BlockSize;\r
 \r
-  Private->BlockIo.Reset        = PartitionReset;\r
-  Private->BlockIo.ReadBlocks   = PartitionReadBlocks;\r
-  Private->BlockIo.WriteBlocks  = PartitionWriteBlocks;\r
-  Private->BlockIo.FlushBlocks  = PartitionFlushBlocks;\r
+  Private->Media2.IoAlign   = 0;\r
+  Private->Media2.LogicalPartition = TRUE;\r
+  Private->Media2.LastBlock = Private->Media.LastBlock;\r
+  Private->Media2.BlockSize = (UINT32) BlockSize;\r
 \r
-  Private->DevicePath           = AppendDevicePathNode (ParentDevicePath, DevicePathNode);\r
+  //\r
+  // Per UEFI Spec, LowestAlignedLba, LogicalBlocksPerPhysicalBlock and OptimalTransferLengthGranularity must be 0\r
+  //  for logical partitions.\r
+  //\r
+  if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION2) {\r
+    Private->Media.LowestAlignedLba               = 0;\r
+    Private->Media.LogicalBlocksPerPhysicalBlock  = 0;\r
+    Private->Media2.LowestAlignedLba              = 0;\r
+    Private->Media2.LogicalBlocksPerPhysicalBlock = 0;\r
+    if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION3) {\r
+      Private->Media.OptimalTransferLengthGranularity  = 0;\r
+      Private->Media2.OptimalTransferLengthGranularity = 0;\r
+    }\r
+  }\r
+\r
+  Private->DevicePath     = AppendDevicePathNode (ParentDevicePath, DevicePathNode);\r
 \r
   if (Private->DevicePath == NULL) {\r
     FreePool (Private);\r
     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
-  Status = gBS->InstallMultipleProtocolInterfaces (\r
-                  &Private->Handle,\r
-                  &gEfiDevicePathProtocolGuid,\r
-                  Private->DevicePath,\r
-                  &gEfiBlockIoProtocolGuid,\r
-                  &Private->BlockIo,\r
-                  Private->EspGuid,\r
-                  NULL,\r
-                  NULL\r
-                  );\r
+  if (Private->DiskIo2 != NULL) {\r
+    Status = gBS->InstallMultipleProtocolInterfaces (\r
+                    &Private->Handle,\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
+  } else {\r
+    Status = gBS->InstallMultipleProtocolInterfaces (\r
+                    &Private->Handle,\r
+                    &gEfiDevicePathProtocolGuid,\r
+                    Private->DevicePath,\r
+                    &gEfiBlockIoProtocolGuid,\r
+                    &Private->BlockIo,\r
+                    &gEfiPartitionInfoProtocolGuid,\r
+                    &Private->PartitionInfo,\r
+                    TypeGuid,\r
+                    NULL,\r
+                    NULL\r
+                    );\r
+  }\r
 \r
   if (!EFI_ERROR (Status)) {\r
     //\r
@@ -676,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
@@ -709,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