Index: /trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/PartitionDxe/Apple.c
===================================================================
--- /trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/PartitionDxe/Apple.c	(revision 42653)
+++ /trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/PartitionDxe/Apple.c	(revision 42653)
@@ -0,0 +1,220 @@
+/* $Id$ */
+/** @file
+ * Apple.c
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "Partition.h"
+
+#define DPISTRLEN       32
+
+#pragma pack(1)
+typedef struct APPLE_PT_HEADER {
+    UINT16      sbSig;          /* must be BE 0x4552 */
+    UINT16      sbBlkSize;      /* block size of device */
+    UINT32      sbBlkCount;     /* number of blocks on device */
+    UINT16      sbDevType;      /* device type */
+    UINT16      sbDevId;        /* device id */
+    UINT32      sbData;         /* not used */
+    UINT16      sbDrvrCount;    /* driver descriptor count */
+    UINT16      sbMap[247];     /* descriptor map */
+} APPLE_PT_HEADER;
+
+typedef struct APPLE_PT_ENTRY  {
+    UINT16       signature          ; /* must be BE 0x504D for new style PT */
+    UINT16       reserved_1         ;
+    UINT32       map_entries        ; /* how many PT entries are there */
+    UINT32       pblock_start       ; /* first physical block */
+    UINT32       pblocks            ; /* number of physical blocks */
+    char         name[DPISTRLEN]    ; /* name of partition */
+    char         type[DPISTRLEN]    ; /* type of partition */
+    /* Some more data we don't really need */
+} APPLE_PT_ENTRY;
+#pragma pack()
+
+static UINT16
+be16_to_cpu(UINT16 x)
+{
+    return SwapBytes16(x);
+}
+
+static UINT32
+be32_to_cpu(UINT32 x)
+{
+    return SwapBytes32(x);
+}
+
+
+/**
+  Install child handles if the Handle supports Apple partition table format.
+
+  @param[in]  This        Calling context.
+  @param[in]  Handle      Parent Handle
+  @param[in]  DiskIo      Parent DiskIo interface
+  @param[in]  BlockIo     Parent BlockIo interface
+  @param[in]  DevicePath  Parent Device Path
+
+
+  @retval EFI_SUCCESS         Child handle(s) was added
+  @retval EFI_MEDIA_CHANGED   Media changed Detected
+  @retval other               no child handle was added
+
+**/
+EFI_STATUS
+PartitionInstallAppleChildHandles (
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN  EFI_HANDLE                   Handle,
+  IN  EFI_DISK_IO_PROTOCOL         *DiskIo,
+  IN  EFI_BLOCK_IO_PROTOCOL        *BlockIo,
+  IN  EFI_BLOCK_IO2_PROTOCOL       *BlockIo2,
+  IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath
+  )
+{
+  EFI_STATUS                Status;
+  UINT32                    Lba;
+  EFI_BLOCK_IO_MEDIA       *Media;
+  VOID                     *Block;
+  //UINTN                   MaxIndex;
+  /** @todo: wrong, as this PT can be on both HDD or CD */
+  CDROM_DEVICE_PATH         CdDev;
+  //EFI_DEVICE_PATH_PROTOCOL  Dev;
+  EFI_STATUS                Found;
+  UINT32                    Partition;
+  UINT32                    PartitionEntries;
+  UINT32                    VolSpaceSize;
+  UINT32                    SubBlockSize;
+  UINT32                    BlkPerSec;
+
+  LogFlowFuncMarkDP(DevicePath);
+  Found         = EFI_NOT_FOUND;
+  Media         = BlockIo->Media;
+  VolSpaceSize  = 0;
+
+  Block = AllocatePool ((UINTN) Media->BlockSize);
+
+  if (Block == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  do {
+      APPLE_PT_HEADER * Header;
+
+      /* read PT header first */
+      Lba = 0;
+
+      Status = DiskIo->ReadDisk (
+                       DiskIo,
+                       Media->MediaId,
+                       MultU64x32 (Lba, Media->BlockSize),
+                       Media->BlockSize,
+                       Block
+                       );
+      if (EFI_ERROR (Status))
+      {
+          Found = Status;
+          break;
+      }
+
+      Header = (APPLE_PT_HEADER *)Block;
+      if (be16_to_cpu(Header->sbSig) != 0x4552)
+      {
+          break;
+      }
+      SubBlockSize = be16_to_cpu(Header->sbBlkSize);
+      BlkPerSec    = Media->BlockSize / SubBlockSize;
+
+      /* Fail if media block size isn't an exact multiple */
+      if (Media->BlockSize != SubBlockSize * BlkPerSec)
+      {
+          break;
+      }
+
+      /* Now iterate over PT entries and install child handles */
+      PartitionEntries = 1;
+      for (Partition = 1; Partition <= PartitionEntries; Partition++)
+      {
+          APPLE_PT_ENTRY * Entry;
+          UINT32 StartLba;
+          UINT32 SizeLbs;
+
+          Status = DiskIo->ReadDisk (
+                       DiskIo,
+                       Media->MediaId,
+                       MultU64x32 (Partition, SubBlockSize),
+                       SubBlockSize,
+                       Block
+                       );
+
+          if (EFI_ERROR (Status)) {
+              Status = EFI_NOT_FOUND;
+              goto done; /* would break, but ... */
+          }
+
+          Entry = (APPLE_PT_ENTRY *)Block;
+
+          if (be16_to_cpu(Entry->signature) != 0x504D)
+          {
+              Print(L"Not a new PT entry: %x", Entry->signature);
+              continue;
+          }
+
+          /* First partition contains partitions count */
+          if (Partition == 1)
+          {
+             PartitionEntries  = be32_to_cpu(Entry->map_entries);
+          }
+
+          StartLba = be32_to_cpu(Entry->pblock_start);
+          SizeLbs  = be32_to_cpu(Entry->pblocks);
+
+          if (0 && CompareMem("Apple_HFS", Entry->type, 10) == 0)
+              Print(L"HFS partition (%d of %d) at LBA 0x%x size=%dM\n",
+                    Partition, PartitionEntries, StartLba,
+                    (UINT32)(MultU64x32(SizeLbs, SubBlockSize) / (1024 * 1024)));
+
+          ZeroMem (&CdDev, sizeof (CdDev));
+          CdDev.Header.Type     = MEDIA_DEVICE_PATH;
+          CdDev.Header.SubType  = MEDIA_CDROM_DP;
+          SetDevicePathNodeLength (&CdDev.Header, sizeof (CdDev));
+
+          CdDev.BootEntry = 0;
+          /* Convert from partition to media blocks */
+          CdDev.PartitionStart = StartLba / BlkPerSec;  /* start, LBA */
+          CdDev.PartitionSize  = SizeLbs / BlkPerSec;   /* size,  LBs */
+
+          Status = PartitionInstallChildHandle (
+              This,
+              Handle,
+              DiskIo,
+              BlockIo,
+              BlockIo2,
+              DevicePath,
+              (EFI_DEVICE_PATH_PROTOCOL *) &CdDev,
+              CdDev.PartitionStart,
+              CdDev.PartitionStart + CdDev.PartitionSize - 1,
+              SubBlockSize,
+              FALSE);
+
+          if (!EFI_ERROR (Status)) {
+              Found = EFI_SUCCESS;
+          }
+      }
+
+  } while (0);
+
+ done:
+  FreePool (Block);
+
+  return Found;
+}
Index: /trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/PartitionDxe/ComponentName.c
===================================================================
--- /trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/PartitionDxe/ComponentName.c	(revision 42653)
+++ /trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/PartitionDxe/ComponentName.c	(revision 42653)
@@ -0,0 +1,205 @@
+/* $Id$ */
+/** @file
+ * ComponentName,c
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/** @file
+  UEFI Component Name protocol for Partition driver.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+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.
+
+**/
+
+#include "Partition.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gPartitionComponentName = {
+  PartitionComponentNameGetDriverName,
+  PartitionComponentNameGetControllerName,
+  "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gPartitionComponentName2 = {
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) PartitionComponentNameGetDriverName,
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) PartitionComponentNameGetControllerName,
+  "en"
+};
+
+//
+// Driver name table for Partition module.
+// It is shared by the implementation of ComponentName & ComponentName2 Protocol.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mPartitionDriverNameTable[] = {
+  {
+    "eng;en",
+    L"Partition Driver(MBR/GPT/El Torito)"
+  },
+  {
+    NULL,
+    NULL
+  }
+};
+
+
+
+/**
+  Retrieves a Unicode string that is the user readable name of the driver.
+
+  This function retrieves the user readable name of a driver in the form of a
+  Unicode string. If the driver specified by This has a user readable name in
+  the language specified by Language, then a pointer to the driver name is
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+  by This does not support the language specified by Language,
+  then EFI_UNSUPPORTED is returned.
+
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  Language[in]          A pointer to a Null-terminated ASCII string
+                                array indicating the language. This is the
+                                language of the driver name that the caller is
+                                requesting, and it must match one of the
+                                languages specified in SupportedLanguages. The
+                                number of languages supported by a driver is up
+                                to the driver writer. Language is specified
+                                in RFC 4646 or ISO 639-2 language code format.
+
+  @param  DriverName[out]       A pointer to the Unicode string to return.
+                                This Unicode string is the name of the
+                                driver specified by This in the language
+                                specified by Language.
+
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by
+                                This and the language specified by Language was
+                                returned in DriverName.
+
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support
+                                the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionComponentNameGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  CHAR8                        *Language,
+  OUT CHAR16                       **DriverName
+  )
+{
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           mPartitionDriverNameTable,
+           DriverName,
+           (BOOLEAN)(This == &gPartitionComponentName)
+           );
+}
+
+
+/**
+  Retrieves a Unicode string that is the user readable name of the controller
+  that is being managed by a driver.
+
+  This function retrieves the user readable name of the controller specified by
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the
+  driver specified by This has a user readable name in the language specified by
+  Language, then a pointer to the controller name is returned in ControllerName,
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently
+  managing the controller specified by ControllerHandle and ChildHandle,
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  ControllerHandle[in]  The handle of a controller that the driver
+                                specified by This is managing.  This handle
+                                specifies the controller whose name is to be
+                                returned.
+
+  @param  ChildHandle[in]       The handle of the child controller to retrieve
+                                the name of.  This is an optional parameter that
+                                may be NULL.  It will be NULL for device
+                                drivers.  It will also be NULL for a bus drivers
+                                that wish to retrieve the name of the bus
+                                controller.  It will not be NULL for a bus
+                                driver that wishes to retrieve the name of a
+                                child controller.
+
+  @param  Language[in]          A pointer to a Null-terminated ASCII string
+                                array indicating the language.  This is the
+                                language of the driver name that the caller is
+                                requesting, and it must match one of the
+                                languages specified in SupportedLanguages. The
+                                number of languages supported by a driver is up
+                                to the driver writer. Language is specified in
+                                RFC 4646 or ISO 639-2 language code format.
+
+  @param  ControllerName[out]   A pointer to the Unicode string to return.
+                                This Unicode string is the name of the
+                                controller specified by ControllerHandle and
+                                ChildHandle in the language specified by
+                                Language from the point of view of the driver
+                                specified by This.
+
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in
+                                the language specified by Language for the
+                                driver specified by This was returned in
+                                DriverName.
+
+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+                                EFI_HANDLE.
+
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently
+                                managing the controller specified by
+                                ControllerHandle and ChildHandle.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support
+                                the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionComponentNameGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
+  IN  EFI_HANDLE                                      ControllerHandle,
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
+  IN  CHAR8                                           *Language,
+  OUT CHAR16                                          **ControllerName
+  )
+{
+  return EFI_UNSUPPORTED;
+}
Index: /trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/PartitionDxe/ElTorito.c
===================================================================
--- /trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/PartitionDxe/ElTorito.c	(revision 42653)
+++ /trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/PartitionDxe/ElTorito.c	(revision 42653)
@@ -0,0 +1,297 @@
+/* $Id$ */
+/** @file
+ * ElTorito.c
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/** @file
+  Decode an El Torito formatted CD-ROM
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+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.
+
+**/
+
+
+#include "Partition.h"
+
+
+/**
+  Install child handles if the Handle supports El Torito format.
+
+  @param[in]  This        Calling context.
+  @param[in]  Handle      Parent Handle.
+  @param[in]  DiskIo      Parent DiskIo interface.
+  @param[in]  BlockIo     Parent BlockIo interface.
+  @param[in]  BlockIo2    Parent BlockIo2 interface.
+  @param[in]  DevicePath  Parent Device Path
+
+
+  @retval EFI_SUCCESS         Child handle(s) was added.
+  @retval EFI_MEDIA_CHANGED   Media changed Detected.
+  @retval other               no child handle was added.
+
+**/
+EFI_STATUS
+PartitionInstallElToritoChildHandles (
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN  EFI_HANDLE                   Handle,
+  IN  EFI_DISK_IO_PROTOCOL         *DiskIo,
+  IN  EFI_BLOCK_IO_PROTOCOL        *BlockIo,
+  IN  EFI_BLOCK_IO2_PROTOCOL       *BlockIo2,
+  IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath
+  )
+{
+  EFI_STATUS              Status;
+  UINT32                  VolDescriptorLba;
+  UINT32                  Lba;
+  EFI_BLOCK_IO_MEDIA      *Media;
+  CDROM_VOLUME_DESCRIPTOR *VolDescriptor;
+  ELTORITO_CATALOG        *Catalog;
+  UINTN                   Check;
+  UINTN                   Index;
+  UINTN                   BootEntry;
+  UINTN                   MaxIndex;
+  UINT16                  *CheckBuffer;
+  CDROM_DEVICE_PATH       CdDev;
+  UINT32                  SubBlockSize;
+  UINT32                  SectorCount;
+  EFI_STATUS              Found;
+  UINT32                  VolSpaceSize;
+
+  LogFlowFuncMarkDP(DevicePath);
+  Found         = EFI_NOT_FOUND;
+  Media         = BlockIo->Media;
+
+  VolSpaceSize  = 0;
+
+  //
+  // CD_ROM has the fixed block size as 2048 bytes
+  //
+  if (Media->BlockSize != 2048) {
+    return EFI_NOT_FOUND;
+  }
+
+  VolDescriptor = AllocatePool ((UINTN) Media->BlockSize);
+
+  if (VolDescriptor == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  Catalog = (ELTORITO_CATALOG *) VolDescriptor;
+
+  //
+  // the ISO-9660 volume descriptor starts at 32k on the media
+  // and CD_ROM has the fixed block size as 2048 bytes, so...
+  //
+  //
+  // ((16*2048) / Media->BlockSize) - 1;
+  //
+  VolDescriptorLba = 15;
+  //
+  // Loop: handle one volume descriptor per time
+  //
+  while (TRUE) {
+
+    VolDescriptorLba += 1;
+    if (VolDescriptorLba > Media->LastBlock) {
+      //
+      // We are pointing past the end of the device so exit
+      //
+      break;
+    }
+
+    Status = DiskIo->ReadDisk (
+                       DiskIo,
+                       Media->MediaId,
+                       MultU64x32 (VolDescriptorLba, Media->BlockSize),
+                       Media->BlockSize,
+                       VolDescriptor
+                       );
+    if (EFI_ERROR (Status)) {
+      Found = Status;
+      break;
+    }
+    //
+    // Check for valid volume descriptor signature
+    //
+    if (VolDescriptor->Unknown.Type == CDVOL_TYPE_END ||
+        CompareMem (VolDescriptor->Unknown.Id, CDVOL_ID, sizeof (VolDescriptor->Unknown.Id)) != 0
+        ) {
+      //
+      // end of Volume descriptor list
+      //
+      break;
+    }
+    //
+    // Read the Volume Space Size from Primary Volume Descriptor 81-88 byte,
+    // the 32-bit numerical values is stored in Both-byte orders
+    //
+    if (VolDescriptor->PrimaryVolume.Type == CDVOL_TYPE_CODED) {
+      VolSpaceSize = VolDescriptor->PrimaryVolume.VolSpaceSize[0];
+    }
+    //
+    // Is it an El Torito volume descriptor?
+    //
+    if (CompareMem (VolDescriptor->BootRecordVolume.SystemId, CDVOL_ELTORITO_ID, sizeof (CDVOL_ELTORITO_ID) - 1) != 0) {
+      continue;
+    }
+    //
+    // Read in the boot El Torito boot catalog
+    //
+    Lba = UNPACK_INT32 (VolDescriptor->BootRecordVolume.EltCatalog);
+    if (Lba > Media->LastBlock) {
+      continue;
+    }
+
+    Status = DiskIo->ReadDisk (
+                       DiskIo,
+                       Media->MediaId,
+                       MultU64x32 (Lba, Media->BlockSize),
+                       Media->BlockSize,
+                       Catalog
+                       );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "EltCheckDevice: error reading catalog %r\n", Status));
+      continue;
+    }
+    //
+    // We don't care too much about the Catalog header's contents, but we do want
+    // to make sure it looks like a Catalog header
+    //
+    if (Catalog->Catalog.Indicator != ELTORITO_ID_CATALOG || Catalog->Catalog.Id55AA != 0xAA55) {
+      DEBUG ((EFI_D_ERROR, "EltCheckBootCatalog: El Torito boot catalog header IDs not correct\n"));
+      continue;
+    }
+
+    Check       = 0;
+    CheckBuffer = (UINT16 *) Catalog;
+    for (Index = 0; Index < sizeof (ELTORITO_CATALOG) / sizeof (UINT16); Index += 1) {
+      Check += CheckBuffer[Index];
+    }
+
+    if ((Check & 0xFFFF) != 0) {
+      DEBUG ((EFI_D_ERROR, "EltCheckBootCatalog: El Torito boot catalog header checksum failed\n"));
+      continue;
+    }
+
+    MaxIndex = Media->BlockSize / sizeof (ELTORITO_CATALOG);
+    for (Index = 1, BootEntry = 1; Index < MaxIndex; Index += 1) {
+      //
+      // Next entry
+      //
+      Catalog += 1;
+
+      //
+      // Check this entry
+      //
+      if (Catalog->Boot.Indicator != ELTORITO_ID_SECTION_BOOTABLE || Catalog->Boot.Lba == 0) {
+        continue;
+      }
+
+      SubBlockSize  = 512;
+      SectorCount   = Catalog->Boot.SectorCount;
+
+      switch (Catalog->Boot.MediaType) {
+
+      case ELTORITO_NO_EMULATION:
+        SubBlockSize = Media->BlockSize;
+        break;
+
+      case ELTORITO_HARD_DISK:
+        break;
+
+      case ELTORITO_12_DISKETTE:
+        SectorCount = 0x50 * 0x02 * 0x0F;
+        break;
+
+      case ELTORITO_14_DISKETTE:
+        SectorCount = 0x50 * 0x02 * 0x12;
+        break;
+
+      case ELTORITO_28_DISKETTE:
+        SectorCount = 0x50 * 0x02 * 0x24;
+        break;
+
+      default:
+        DEBUG ((EFI_D_INIT, "EltCheckDevice: unsupported El Torito boot media type %x\n", Catalog->Boot.MediaType));
+        SectorCount   = 0;
+        SubBlockSize  = Media->BlockSize;
+        break;
+      }
+      //
+      // Create child device handle
+      //
+      CdDev.Header.Type     = MEDIA_DEVICE_PATH;
+      CdDev.Header.SubType  = MEDIA_CDROM_DP;
+      SetDevicePathNodeLength (&CdDev.Header, sizeof (CdDev));
+
+      if (Index == 1) {
+        //
+        // This is the initial/default entry
+        //
+        BootEntry = 0;
+      }
+
+      CdDev.BootEntry = (UINT32) BootEntry;
+      BootEntry++;
+      CdDev.PartitionStart = Catalog->Boot.Lba;
+      if (SectorCount < 2) {
+        //
+        // When the SectorCount < 2, set the Partition as the whole CD.
+        //
+        if (VolSpaceSize > (Media->LastBlock + 1)) {
+          CdDev.PartitionSize = (UINT32)(Media->LastBlock - Catalog->Boot.Lba + 1);
+        } else {
+          CdDev.PartitionSize = (UINT32)(VolSpaceSize - Catalog->Boot.Lba);
+        }
+      } else {
+        CdDev.PartitionSize = DivU64x32 (
+                                MultU64x32 (
+                                  SectorCount,
+                                  SubBlockSize
+                                  ) + Media->BlockSize - 1,
+                                Media->BlockSize
+                                );
+      }
+
+      Status = PartitionInstallChildHandle (
+                This,
+                Handle,
+                DiskIo,
+                BlockIo,
+                BlockIo2,
+                DevicePath,
+                (EFI_DEVICE_PATH_PROTOCOL *) &CdDev,
+                Catalog->Boot.Lba,
+                Catalog->Boot.Lba + CdDev.PartitionSize - 1,
+                SubBlockSize,
+                FALSE
+                );
+      if (!EFI_ERROR (Status)) {
+        Found = EFI_SUCCESS;
+      }
+    }
+  }
+
+  FreePool (VolDescriptor);
+
+  return Found;
+}
Index: /trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/PartitionDxe/Gpt.c
===================================================================
--- /trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/PartitionDxe/Gpt.c	(revision 42653)
+++ /trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/PartitionDxe/Gpt.c	(revision 42653)
@@ -0,0 +1,847 @@
+/* $Id$ */
+/** @file
+ * Gpt.c
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/** @file
+  Decode a hard disk partitioned with the GPT scheme in the UEFI 2.0
+  specification.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+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.
+
+**/
+
+
+#include "Partition.h"
+
+/**
+  Install child handles if the Handle supports GPT partition structure.
+
+  @param[in]  BlockIo     Parent BlockIo interface.
+  @param[in]  DiskIo      Disk Io protocol.
+  @param[in]  Lba         The starting Lba of the Partition Table
+  @param[out] PartHeader  Stores the partition table that is read
+
+  @retval TRUE      The partition table is valid
+  @retval FALSE     The partition table is not valid
+
+**/
+BOOLEAN
+PartitionValidGptTable (
+  IN  EFI_BLOCK_IO_PROTOCOL       *BlockIo,
+  IN  EFI_DISK_IO_PROTOCOL        *DiskIo,
+  IN  EFI_LBA                     Lba,
+  OUT EFI_PARTITION_TABLE_HEADER  *PartHeader
+  );
+
+/**
+  Check if the CRC field in the Partition table header is valid
+  for Partition entry array.
+
+  @param[in]  BlockIo     Parent BlockIo interface
+  @param[in]  DiskIo      Disk Io Protocol.
+  @param[in]  PartHeader  Partition table header structure
+
+  @retval TRUE      the CRC is valid
+  @retval FALSE     the CRC is invalid
+
+**/
+BOOLEAN
+PartitionCheckGptEntryArrayCRC (
+  IN  EFI_BLOCK_IO_PROTOCOL       *BlockIo,
+  IN  EFI_DISK_IO_PROTOCOL        *DiskIo,
+  IN  EFI_PARTITION_TABLE_HEADER  *PartHeader
+  );
+
+
+/**
+  Restore Partition Table to its alternate place
+  (Primary -> Backup or Backup -> Primary).
+
+  @param[in]  BlockIo     Parent BlockIo interface.
+  @param[in]  DiskIo      Disk Io Protocol.
+  @param[in]  PartHeader  Partition table header structure.
+
+  @retval TRUE      Restoring succeeds
+  @retval FALSE     Restoring failed
+
+**/
+BOOLEAN
+PartitionRestoreGptTable (
+  IN  EFI_BLOCK_IO_PROTOCOL       *BlockIo,
+  IN  EFI_DISK_IO_PROTOCOL        *DiskIo,
+  IN  EFI_PARTITION_TABLE_HEADER  *PartHeader
+  );
+
+
+/**
+  Restore Partition Table to its alternate place.
+  (Primary -> Backup or Backup -> Primary)
+
+  @param[in]    PartHeader    Partition table header structure
+  @param[in]    PartEntry     The partition entry array
+  @param[out]   PEntryStatus  the partition entry status array
+                              recording the status of each partition
+
+**/
+VOID
+PartitionCheckGptEntry (
+  IN  EFI_PARTITION_TABLE_HEADER  *PartHeader,
+  IN  EFI_PARTITION_ENTRY         *PartEntry,
+  OUT EFI_PARTITION_ENTRY_STATUS  *PEntryStatus
+  );
+
+
+/**
+  Checks the CRC32 value in the table header.
+
+  @param  MaxSize   Max Size limit
+  @param  Size      The size of the table
+  @param  Hdr       Table to check
+
+  @return TRUE    CRC Valid
+  @return FALSE   CRC Invalid
+
+**/
+BOOLEAN
+PartitionCheckCrcAltSize (
+  IN UINTN                 MaxSize,
+  IN UINTN                 Size,
+  IN OUT EFI_TABLE_HEADER  *Hdr
+  );
+
+
+/**
+  Checks the CRC32 value in the table header.
+
+  @param  MaxSize   Max Size limit
+  @param  Hdr       Table to check
+
+  @return TRUE      CRC Valid
+  @return FALSE     CRC Invalid
+
+**/
+BOOLEAN
+PartitionCheckCrc (
+  IN UINTN                 MaxSize,
+  IN OUT EFI_TABLE_HEADER  *Hdr
+  );
+
+
+/**
+  Updates the CRC32 value in the table header.
+
+  @param  Size   The size of the table
+  @param  Hdr    Table to update
+
+**/
+VOID
+PartitionSetCrcAltSize (
+  IN UINTN                 Size,
+  IN OUT EFI_TABLE_HEADER  *Hdr
+  );
+
+
+/**
+  Updates the CRC32 value in the table header.
+
+  @param  Hdr    Table to update
+
+**/
+VOID
+PartitionSetCrc (
+  IN OUT EFI_TABLE_HEADER *Hdr
+  );
+
+/**
+  Install child handles if the Handle supports GPT partition structure.
+
+  @param[in]  This       Calling context.
+  @param[in]  Handle     Parent Handle.
+  @param[in]  DiskIo     Parent DiskIo interface.
+  @param[in]  BlockIo    Parent BlockIo interface.
+  @param[in]  BlockIo2   Parent BlockIo2 interface.
+  @param[in]  DevicePath Parent Device Path.
+
+  @retval EFI_SUCCESS           Valid GPT disk.
+  @retval EFI_MEDIA_CHANGED     Media changed Detected.
+  @retval other                 Not a valid GPT disk.
+
+**/
+EFI_STATUS
+PartitionInstallGptChildHandles (
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN  EFI_HANDLE                   Handle,
+  IN  EFI_DISK_IO_PROTOCOL         *DiskIo,
+  IN  EFI_BLOCK_IO_PROTOCOL        *BlockIo,
+  IN  EFI_BLOCK_IO2_PROTOCOL       *BlockIo2,
+  IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath
+  )
+{
+  EFI_STATUS                  Status;
+  UINT32                      BlockSize;
+  EFI_LBA                     LastBlock;
+  MASTER_BOOT_RECORD          *ProtectiveMbr;
+  EFI_PARTITION_TABLE_HEADER  *PrimaryHeader;
+  EFI_PARTITION_TABLE_HEADER  *BackupHeader;
+  EFI_PARTITION_ENTRY         *PartEntry;
+  EFI_PARTITION_ENTRY         *Entry;
+  EFI_PARTITION_ENTRY_STATUS  *PEntryStatus;
+  UINTN                       Index;
+  EFI_STATUS                  GptValidStatus;
+  HARDDRIVE_DEVICE_PATH       HdDev;
+  UINT32                      MediaId;
+
+  LogFlowFuncMarkDP(DevicePath);
+  ProtectiveMbr = NULL;
+  PrimaryHeader = NULL;
+  BackupHeader  = NULL;
+  PartEntry     = NULL;
+  PEntryStatus  = NULL;
+
+  BlockSize     = BlockIo->Media->BlockSize;
+  LastBlock     = BlockIo->Media->LastBlock;
+  MediaId       = BlockIo->Media->MediaId;
+
+  DEBUG ((EFI_D_INFO, " BlockSize : %d \n", BlockSize));
+  DEBUG ((EFI_D_INFO, " LastBlock : %lx \n", LastBlock));
+
+  GptValidStatus = EFI_NOT_FOUND;
+
+  //
+  // Allocate a buffer for the Protective MBR
+  //
+  ProtectiveMbr = AllocatePool (BlockSize);
+  if (ProtectiveMbr == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  //
+  // Read the Protective MBR from LBA #0
+  //
+  Status = DiskIo->ReadDisk (
+                     DiskIo,
+                     MediaId,
+                     0,
+                     BlockSize,
+                     ProtectiveMbr
+                     );
+  if (EFI_ERROR (Status)) {
+    GptValidStatus = Status;
+    goto Done;
+  }
+
+  //
+  // Verify that the Protective MBR is valid
+  //
+  for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
+    if (ProtectiveMbr->Partition[Index].BootIndicator == 0x00 &&
+        ProtectiveMbr->Partition[Index].OSIndicator == PMBR_GPT_PARTITION &&
+        UNPACK_UINT32 (ProtectiveMbr->Partition[Index].StartingLBA) == 1
+        ) {
+      break;
+    }
+  }
+  if (Index == MAX_MBR_PARTITIONS) {
+    goto Done;
+  }
+
+  //
+  // Allocate the GPT structures
+  //
+  PrimaryHeader = AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER));
+  if (PrimaryHeader == NULL) {
+    goto Done;
+  }
+
+  BackupHeader = AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER));
+  if (BackupHeader == NULL) {
+    goto Done;
+  }
+
+  //
+  // Check primary and backup partition tables
+  //
+  if (!PartitionValidGptTable (BlockIo, DiskIo, PRIMARY_PART_HEADER_LBA, PrimaryHeader)) {
+    DEBUG ((EFI_D_INFO, " Not Valid primary partition table\n"));
+
+    if (!PartitionValidGptTable (BlockIo, DiskIo, LastBlock, BackupHeader)) {
+      DEBUG ((EFI_D_INFO, " Not Valid backup partition table\n"));
+      goto Done;
+    } else {
+      DEBUG ((EFI_D_INFO, " Valid backup partition table\n"));
+      DEBUG ((EFI_D_INFO, " Restore primary partition table by the backup\n"));
+      if (!PartitionRestoreGptTable (BlockIo, DiskIo, BackupHeader)) {
+        DEBUG ((EFI_D_INFO, " Restore primary partition table error\n"));
+      }
+
+      if (PartitionValidGptTable (BlockIo, DiskIo, BackupHeader->AlternateLBA, PrimaryHeader)) {
+        DEBUG ((EFI_D_INFO, " Restore backup partition table success\n"));
+      }
+    }
+  } else if (!PartitionValidGptTable (BlockIo, DiskIo, PrimaryHeader->AlternateLBA, BackupHeader)) {
+    DEBUG ((EFI_D_INFO, " Valid primary and !Valid backup partition table\n"));
+    DEBUG ((EFI_D_INFO, " Restore backup partition table by the primary\n"));
+    if (!PartitionRestoreGptTable (BlockIo, DiskIo, PrimaryHeader)) {
+      DEBUG ((EFI_D_INFO, " Restore  backup partition table error\n"));
+    }
+
+    if (PartitionValidGptTable (BlockIo, DiskIo, PrimaryHeader->AlternateLBA, BackupHeader)) {
+      DEBUG ((EFI_D_INFO, " Restore backup partition table success\n"));
+    }
+
+  }
+
+  DEBUG ((EFI_D_INFO, " Valid primary and Valid backup partition table\n"));
+
+  //
+  // Read the EFI Partition Entries
+  //
+  PartEntry = AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry);
+  if (PartEntry == NULL) {
+    DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
+    goto Done;
+  }
+
+  Status = DiskIo->ReadDisk (
+                     DiskIo,
+                     MediaId,
+                     MultU64x32(PrimaryHeader->PartitionEntryLBA, BlockSize),
+                     PrimaryHeader->NumberOfPartitionEntries * (PrimaryHeader->SizeOfPartitionEntry),
+                     PartEntry
+                     );
+  if (EFI_ERROR (Status)) {
+    GptValidStatus = Status;
+    DEBUG ((EFI_D_ERROR, " Partition Entry ReadDisk error\n"));
+    goto Done;
+  }
+
+  DEBUG ((EFI_D_INFO, " Partition entries read block success\n"));
+
+  DEBUG ((EFI_D_INFO, " Number of partition entries: %d\n", PrimaryHeader->NumberOfPartitionEntries));
+
+  PEntryStatus = AllocateZeroPool (PrimaryHeader->NumberOfPartitionEntries * sizeof (EFI_PARTITION_ENTRY_STATUS));
+  if (PEntryStatus == NULL) {
+    DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
+    goto Done;
+  }
+
+  //
+  // Check the integrity of partition entries
+  //
+  PartitionCheckGptEntry (PrimaryHeader, PartEntry, PEntryStatus);
+
+  //
+  // If we got this far the GPT layout of the disk is valid and we should return true
+  //
+  GptValidStatus = EFI_SUCCESS;
+
+  //
+  // Create child device handles
+  //
+  for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {
+    Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartEntry + Index * PrimaryHeader->SizeOfPartitionEntry);
+    if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid) ||
+        PEntryStatus[Index].OutOfRange ||
+        PEntryStatus[Index].Overlap ||
+        PEntryStatus[Index].OsSpecific
+        ) {
+      //
+      // Don't use null EFI Partition Entries, Invalid Partition Entries or OS specific
+      // partition Entries
+      //
+      continue;
+    }
+
+    ZeroMem (&HdDev, sizeof (HdDev));
+    HdDev.Header.Type     = MEDIA_DEVICE_PATH;
+    HdDev.Header.SubType  = MEDIA_HARDDRIVE_DP;
+    SetDevicePathNodeLength (&HdDev.Header, sizeof (HdDev));
+
+    HdDev.PartitionNumber = (UINT32) Index + 1;
+    HdDev.MBRType         = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
+    HdDev.SignatureType   = SIGNATURE_TYPE_GUID;
+    HdDev.PartitionStart  = Entry->StartingLBA;
+    HdDev.PartitionSize   = Entry->EndingLBA - Entry->StartingLBA + 1;
+    CopyMem (HdDev.Signature, &Entry->UniquePartitionGUID, sizeof (EFI_GUID));
+
+    DEBUG ((EFI_D_INFO, " Index : %d\n", (UINT32) Index));
+    DEBUG ((EFI_D_INFO, " Start LBA : %lx\n", (UINT64) HdDev.PartitionStart));
+    DEBUG ((EFI_D_INFO, " End LBA : %lx\n", (UINT64) Entry->EndingLBA));
+    DEBUG ((EFI_D_INFO, " Partition size: %lx\n", (UINT64) HdDev.PartitionSize));
+    DEBUG ((EFI_D_INFO, " Start : %lx", MultU64x32 (Entry->StartingLBA, BlockSize)));
+    DEBUG ((EFI_D_INFO, " End : %lx\n", MultU64x32 (Entry->EndingLBA, BlockSize)));
+
+    Status = PartitionInstallChildHandle (
+               This,
+               Handle,
+               DiskIo,
+               BlockIo,
+               BlockIo2,
+               DevicePath,
+               (EFI_DEVICE_PATH_PROTOCOL *) &HdDev,
+               Entry->StartingLBA,
+               Entry->EndingLBA,
+               BlockSize,
+               CompareGuid(&Entry->PartitionTypeGUID, &gEfiPartTypeSystemPartGuid)
+               );
+  }
+
+  DEBUG ((EFI_D_INFO, "Prepare to Free Pool\n"));
+
+Done:
+  if (ProtectiveMbr != NULL) {
+    FreePool (ProtectiveMbr);
+  }
+  if (PrimaryHeader != NULL) {
+    FreePool (PrimaryHeader);
+  }
+  if (BackupHeader != NULL) {
+    FreePool (BackupHeader);
+  }
+  if (PartEntry != NULL) {
+    FreePool (PartEntry);
+  }
+  if (PEntryStatus != NULL) {
+    FreePool (PEntryStatus);
+  }
+
+  return GptValidStatus;
+}
+
+/**
+  Install child handles if the Handle supports GPT partition structure.
+
+  @param[in]  BlockIo     Parent BlockIo interface.
+  @param[in]  DiskIo      Disk Io protocol.
+  @param[in]  Lba         The starting Lba of the Partition Table
+  @param[out] PartHeader  Stores the partition table that is read
+
+  @retval TRUE      The partition table is valid
+  @retval FALSE     The partition table is not valid
+
+**/
+BOOLEAN
+PartitionValidGptTable (
+  IN  EFI_BLOCK_IO_PROTOCOL       *BlockIo,
+  IN  EFI_DISK_IO_PROTOCOL        *DiskIo,
+  IN  EFI_LBA                     Lba,
+  OUT EFI_PARTITION_TABLE_HEADER  *PartHeader
+  )
+{
+  EFI_STATUS                  Status;
+  UINT32                      BlockSize;
+  EFI_PARTITION_TABLE_HEADER  *PartHdr;
+  UINT32                      MediaId;
+
+  BlockSize = BlockIo->Media->BlockSize;
+  MediaId   = BlockIo->Media->MediaId;
+  PartHdr   = AllocateZeroPool (BlockSize);
+
+  if (PartHdr == NULL) {
+    DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
+    return FALSE;
+  }
+  //
+  // Read the EFI Partition Table Header
+  //
+  Status = DiskIo->ReadDisk (
+                     DiskIo,
+                     MediaId,
+                     MultU64x32 (Lba, BlockSize),
+                     BlockSize,
+                     PartHdr
+                     );
+  if (EFI_ERROR (Status)) {
+    FreePool (PartHdr);
+    return FALSE;
+  }
+
+  if ((PartHdr->Header.Signature != EFI_PTAB_HEADER_ID) ||
+      !PartitionCheckCrc (BlockSize, &PartHdr->Header) ||
+      PartHdr->MyLBA != Lba
+      ) {
+    DEBUG ((EFI_D_INFO, "Invalid efi partition table header\n"));
+    FreePool (PartHdr);
+    return FALSE;
+  }
+
+  CopyMem (PartHeader, PartHdr, sizeof (EFI_PARTITION_TABLE_HEADER));
+  if (!PartitionCheckGptEntryArrayCRC (BlockIo, DiskIo, PartHeader)) {
+    FreePool (PartHdr);
+    return FALSE;
+  }
+
+  DEBUG ((EFI_D_INFO, " Valid efi partition table header\n"));
+  FreePool (PartHdr);
+  return TRUE;
+}
+
+/**
+  Check if the CRC field in the Partition table header is valid
+  for Partition entry array.
+
+  @param[in]  BlockIo     Parent BlockIo interface
+  @param[in]  DiskIo      Disk Io Protocol.
+  @param[in]  PartHeader  Partition table header structure
+
+  @retval TRUE      the CRC is valid
+  @retval FALSE     the CRC is invalid
+
+**/
+BOOLEAN
+PartitionCheckGptEntryArrayCRC (
+  IN  EFI_BLOCK_IO_PROTOCOL       *BlockIo,
+  IN  EFI_DISK_IO_PROTOCOL        *DiskIo,
+  IN  EFI_PARTITION_TABLE_HEADER  *PartHeader
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       *Ptr;
+  UINT32      Crc;
+  UINTN       Size;
+
+  //
+  // Read the EFI Partition Entries
+  //
+  Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry);
+  if (Ptr == NULL) {
+    DEBUG ((EFI_D_ERROR, " Allocate pool error\n"));
+    return FALSE;
+  }
+
+  Status = DiskIo->ReadDisk (
+                    DiskIo,
+                    BlockIo->Media->MediaId,
+                    MultU64x32(PartHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),
+                    PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
+                    Ptr
+                    );
+  if (EFI_ERROR (Status)) {
+    FreePool (Ptr);
+    return FALSE;
+  }
+
+  Size    = PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry;
+
+  Status  = gBS->CalculateCrc32 (Ptr, Size, &Crc);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "CheckPEntryArrayCRC: Crc calculation failed\n"));
+    FreePool (Ptr);
+    return FALSE;
+  }
+
+  FreePool (Ptr);
+
+  return (BOOLEAN) (PartHeader->PartitionEntryArrayCRC32 == Crc);
+}
+
+
+/**
+  Restore Partition Table to its alternate place
+  (Primary -> Backup or Backup -> Primary).
+
+  @param[in]  BlockIo     Parent BlockIo interface.
+  @param[in]  DiskIo      Disk Io Protocol.
+  @param[in]  PartHeader  Partition table header structure.
+
+  @retval TRUE      Restoring succeeds
+  @retval FALSE     Restoring failed
+
+**/
+BOOLEAN
+PartitionRestoreGptTable (
+  IN  EFI_BLOCK_IO_PROTOCOL       *BlockIo,
+  IN  EFI_DISK_IO_PROTOCOL        *DiskIo,
+  IN  EFI_PARTITION_TABLE_HEADER  *PartHeader
+  )
+{
+  EFI_STATUS                  Status;
+  UINTN                       BlockSize;
+  EFI_PARTITION_TABLE_HEADER  *PartHdr;
+  EFI_LBA                     PEntryLBA;
+  UINT8                       *Ptr;
+  UINT32                      MediaId;
+
+  PartHdr   = NULL;
+  Ptr       = NULL;
+
+  BlockSize = BlockIo->Media->BlockSize;
+  MediaId   = BlockIo->Media->MediaId;
+
+  PartHdr   = AllocateZeroPool (BlockSize);
+
+  if (PartHdr == NULL) {
+    DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
+    return FALSE;
+  }
+
+  PEntryLBA = (PartHeader->MyLBA == PRIMARY_PART_HEADER_LBA) ? \
+                             (PartHeader->LastUsableLBA + 1) : \
+                             (PRIMARY_PART_HEADER_LBA + 1);
+
+  CopyMem (PartHdr, PartHeader, sizeof (EFI_PARTITION_TABLE_HEADER));
+
+  PartHdr->MyLBA              = PartHeader->AlternateLBA;
+  PartHdr->AlternateLBA       = PartHeader->MyLBA;
+  PartHdr->PartitionEntryLBA  = PEntryLBA;
+  PartitionSetCrc ((EFI_TABLE_HEADER *) PartHdr);
+
+  Status = DiskIo->WriteDisk (
+                     DiskIo,
+                     MediaId,
+                     MultU64x32 (PartHdr->MyLBA, (UINT32) BlockSize),
+                     BlockSize,
+                     PartHdr
+                     );
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry);
+  if (Ptr == NULL) {
+    DEBUG ((EFI_D_ERROR, " Allocate pool error\n"));
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Done;
+  }
+
+  Status = DiskIo->ReadDisk (
+                    DiskIo,
+                    MediaId,
+                    MultU64x32(PartHeader->PartitionEntryLBA, (UINT32) BlockSize),
+                    PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
+                    Ptr
+                    );
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  Status = DiskIo->WriteDisk (
+                    DiskIo,
+                    MediaId,
+                    MultU64x32(PEntryLBA, (UINT32) BlockSize),
+                    PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
+                    Ptr
+                    );
+
+Done:
+  FreePool (PartHdr);
+
+  if (Ptr != NULL) {
+    FreePool (Ptr);
+  }
+
+  if (EFI_ERROR (Status)) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/**
+  Restore Partition Table to its alternate place.
+  (Primary -> Backup or Backup -> Primary)
+
+  @param[in]    PartHeader    Partition table header structure
+  @param[in]    PartEntry     The partition entry array
+  @param[out]   PEntryStatus  the partition entry status array
+                              recording the status of each partition
+
+**/
+VOID
+PartitionCheckGptEntry (
+  IN  EFI_PARTITION_TABLE_HEADER  *PartHeader,
+  IN  EFI_PARTITION_ENTRY         *PartEntry,
+  OUT EFI_PARTITION_ENTRY_STATUS  *PEntryStatus
+  )
+{
+  EFI_LBA              StartingLBA;
+  EFI_LBA              EndingLBA;
+  EFI_PARTITION_ENTRY  *Entry;
+  UINTN                Index1;
+  UINTN                Index2;
+
+  DEBUG ((EFI_D_INFO, " start check partition entries\n"));
+  for (Index1 = 0; Index1 < PartHeader->NumberOfPartitionEntries; Index1++) {
+    Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartEntry + Index1 * PartHeader->SizeOfPartitionEntry);
+    if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
+      continue;
+    }
+
+    StartingLBA = Entry->StartingLBA;
+    EndingLBA   = Entry->EndingLBA;
+    if (StartingLBA > EndingLBA ||
+        StartingLBA < PartHeader->FirstUsableLBA ||
+        StartingLBA > PartHeader->LastUsableLBA ||
+        EndingLBA < PartHeader->FirstUsableLBA ||
+        EndingLBA > PartHeader->LastUsableLBA
+        ) {
+      PEntryStatus[Index1].OutOfRange = TRUE;
+      continue;
+    }
+
+    if ((Entry->Attributes & BIT1) != 0) {
+      //
+      // If Bit 1 is set, this indicate that this is an OS specific GUID partition.
+      //
+      PEntryStatus[Index1].OsSpecific = TRUE;
+    }
+
+    for (Index2 = Index1 + 1; Index2 < PartHeader->NumberOfPartitionEntries; Index2++) {
+      Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartEntry + Index2 * PartHeader->SizeOfPartitionEntry);
+      if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
+        continue;
+      }
+
+      if (Entry->EndingLBA >= StartingLBA && Entry->StartingLBA <= EndingLBA) {
+        //
+        // This region overlaps with the Index1'th region
+        //
+        PEntryStatus[Index1].Overlap  = TRUE;
+        PEntryStatus[Index2].Overlap  = TRUE;
+        continue;
+      }
+    }
+  }
+
+  DEBUG ((EFI_D_INFO, " End check partition entries\n"));
+}
+
+
+/**
+  Updates the CRC32 value in the table header.
+
+  @param  Hdr    Table to update
+
+**/
+VOID
+PartitionSetCrc (
+  IN OUT EFI_TABLE_HEADER *Hdr
+  )
+{
+  PartitionSetCrcAltSize (Hdr->HeaderSize, Hdr);
+}
+
+
+/**
+  Updates the CRC32 value in the table header.
+
+  @param  Size   The size of the table
+  @param  Hdr    Table to update
+
+**/
+VOID
+PartitionSetCrcAltSize (
+  IN UINTN                 Size,
+  IN OUT EFI_TABLE_HEADER  *Hdr
+  )
+{
+  UINT32  Crc;
+
+  Hdr->CRC32 = 0;
+  gBS->CalculateCrc32 ((UINT8 *) Hdr, Size, &Crc);
+  Hdr->CRC32 = Crc;
+}
+
+
+/**
+  Checks the CRC32 value in the table header.
+
+  @param  MaxSize   Max Size limit
+  @param  Hdr       Table to check
+
+  @return TRUE      CRC Valid
+  @return FALSE     CRC Invalid
+
+**/
+BOOLEAN
+PartitionCheckCrc (
+  IN UINTN                 MaxSize,
+  IN OUT EFI_TABLE_HEADER  *Hdr
+  )
+{
+  return PartitionCheckCrcAltSize (MaxSize, Hdr->HeaderSize, Hdr);
+}
+
+
+/**
+  Checks the CRC32 value in the table header.
+
+  @param  MaxSize   Max Size limit
+  @param  Size      The size of the table
+  @param  Hdr       Table to check
+
+  @return TRUE    CRC Valid
+  @return FALSE   CRC Invalid
+
+**/
+BOOLEAN
+PartitionCheckCrcAltSize (
+  IN UINTN                 MaxSize,
+  IN UINTN                 Size,
+  IN OUT EFI_TABLE_HEADER  *Hdr
+  )
+{
+  UINT32      Crc;
+  UINT32      OrgCrc;
+  EFI_STATUS  Status;
+
+  Crc = 0;
+
+  if (Size == 0) {
+    //
+    // If header size is 0 CRC will pass so return FALSE here
+    //
+    return FALSE;
+  }
+
+  if ((MaxSize != 0) && (Size > MaxSize)) {
+    DEBUG ((EFI_D_ERROR, "CheckCrc32: Size > MaxSize\n"));
+    return FALSE;
+  }
+  //
+  // clear old crc from header
+  //
+  OrgCrc      = Hdr->CRC32;
+  Hdr->CRC32  = 0;
+
+  Status      = gBS->CalculateCrc32 ((UINT8 *) Hdr, Size, &Crc);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc calculation failed\n"));
+    return FALSE;
+  }
+  //
+  // set results
+  //
+  Hdr->CRC32 = Crc;
+
+  //
+  // return status
+  //
+  DEBUG_CODE_BEGIN ();
+    if (OrgCrc != Crc) {
+      DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc check failed\n"));
+    }
+  DEBUG_CODE_END ();
+
+  return (BOOLEAN) (OrgCrc == Crc);
+}
Index: /trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/PartitionDxe/Mbr.c
===================================================================
--- /trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/PartitionDxe/Mbr.c	(revision 42653)
+++ /trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/PartitionDxe/Mbr.c	(revision 42653)
@@ -0,0 +1,341 @@
+/* $Id$ */
+/** @file
+ * Mbr.c
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/** @file
+  Decode a hard disk partitioned with the legacy MBR found on most PC's
+
+  MBR - Master Boot Record is in the first sector of a partitioned hard disk.
+        The MBR supports four partitions per disk. The MBR also contains legacy
+        code that is not run on an EFI system. The legacy code reads the
+        first sector of the active partition into memory and
+
+  BPB - BIOS Parameter Block is in the first sector of a FAT file system.
+        The BPB contains information about the FAT file system. The BPB is
+        always on the first sector of a media. The first sector also contains
+        the legacy boot strap code.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+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.
+
+**/
+
+#include "Partition.h"
+
+/**
+  Test to see if the Mbr buffer is a valid MBR.
+
+  @param  Mbr         Parent Handle.
+  @param  LastLba     Last Lba address on the device.
+
+  @retval TRUE        Mbr is a Valid MBR.
+  @retval FALSE       Mbr is not a Valid MBR.
+
+**/
+BOOLEAN
+PartitionValidMbr (
+  IN  MASTER_BOOT_RECORD      *Mbr,
+  IN  EFI_LBA                 LastLba
+  )
+{
+  UINT32  StartingLBA;
+  UINT32  EndingLBA;
+  UINT32  NewEndingLBA;
+  INTN    Index1;
+  INTN    Index2;
+  BOOLEAN MbrValid;
+
+  if (Mbr->Signature != MBR_SIGNATURE) {
+    return FALSE;
+  }
+  //
+  // The BPB also has this signature, so it can not be used alone.
+  //
+  MbrValid = FALSE;
+  for (Index1 = 0; Index1 < MAX_MBR_PARTITIONS; Index1++) {
+    if (Mbr->Partition[Index1].OSIndicator == 0x00 || UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) == 0) {
+      continue;
+    }
+
+    MbrValid    = TRUE;
+    StartingLBA = UNPACK_UINT32 (Mbr->Partition[Index1].StartingLBA);
+    EndingLBA   = StartingLBA + UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) - 1;
+    if (EndingLBA > LastLba) {
+      //
+      // Compatibility Errata:
+      //  Some systems try to hide drive space with their INT 13h driver
+      //  This does not hide space from the OS driver. This means the MBR
+      //  that gets created from DOS is smaller than the MBR created from
+      //  a real OS (NT & Win98). This leads to BlockIo->LastBlock being
+      //  wrong on some systems FDISKed by the OS.
+      //
+      // return FALSE since no block devices on a system are implemented
+      // with INT 13h
+      //
+      return FALSE;
+    }
+
+    for (Index2 = Index1 + 1; Index2 < MAX_MBR_PARTITIONS; Index2++) {
+      if (Mbr->Partition[Index2].OSIndicator == 0x00 || UNPACK_UINT32 (Mbr->Partition[Index2].SizeInLBA) == 0) {
+        continue;
+      }
+
+      NewEndingLBA = UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) + UNPACK_UINT32 (Mbr->Partition[Index2].SizeInLBA) - 1;
+      if (NewEndingLBA >= StartingLBA && UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) <= EndingLBA) {
+        //
+        // This region overlaps with the Index1'th region
+        //
+        return FALSE;
+      }
+    }
+  }
+  //
+  // None of the regions overlapped so MBR is O.K.
+  //
+  return MbrValid;
+}
+
+
+/**
+  Install child handles if the Handle supports MBR format.
+
+  @param[in]  This              Calling context.
+  @param[in]  Handle            Parent Handle.
+  @param[in]  DiskIo            Parent DiskIo interface.
+  @param[in]  BlockIo           Parent BlockIo interface.
+  @param[in]  BlockIo2          Parent BlockIo2 interface.
+  @param[in]  DevicePath        Parent Device Path.
+
+  @retval EFI_SUCCESS       A child handle was added.
+  @retval EFI_MEDIA_CHANGED Media change was detected.
+  @retval Others            MBR partition was not found.
+
+**/
+EFI_STATUS
+PartitionInstallMbrChildHandles (
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN  EFI_HANDLE                   Handle,
+  IN  EFI_DISK_IO_PROTOCOL         *DiskIo,
+  IN  EFI_BLOCK_IO_PROTOCOL        *BlockIo,
+  IN  EFI_BLOCK_IO2_PROTOCOL       *BlockIo2,
+  IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath
+  )
+{
+  EFI_STATUS                Status;
+  MASTER_BOOT_RECORD        *Mbr;
+  UINT32                    ExtMbrStartingLba;
+  UINTN                     Index;
+  HARDDRIVE_DEVICE_PATH     HdDev;
+  HARDDRIVE_DEVICE_PATH     ParentHdDev;
+  EFI_STATUS                Found;
+  UINT32                    PartitionNumber;
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePathNode;
+  EFI_DEVICE_PATH_PROTOCOL  *LastDevicePathNode;
+  UINT32                    BlockSize;
+  UINT32                    MediaId;
+  EFI_LBA                   LastBlock;
+
+  Found           = EFI_NOT_FOUND;
+
+  BlockSize = BlockIo->Media->BlockSize;
+  MediaId   = BlockIo->Media->MediaId;
+  LastBlock = BlockIo->Media->LastBlock;
+
+  LogFlowFuncMarkDP(DevicePath);
+  Mbr = AllocatePool (BlockSize);
+  if (Mbr == NULL) {
+    return Found;
+  }
+
+  Status = DiskIo->ReadDisk (
+                     DiskIo,
+                     MediaId,
+                     0,
+                     BlockSize,
+                     Mbr
+                     );
+  if (EFI_ERROR (Status)) {
+    Found = Status;
+    goto Done;
+  }
+  if (!PartitionValidMbr (Mbr, LastBlock)) {
+    goto Done;
+  }
+  //
+  // We have a valid mbr - add each partition
+  //
+  //
+  // Get starting and ending LBA of the parent block device.
+  //
+  LastDevicePathNode = NULL;
+  ZeroMem (&ParentHdDev, sizeof (ParentHdDev));
+  DevicePathNode = DevicePath;
+  while (!IsDevicePathEnd (DevicePathNode)) {
+    LastDevicePathNode  = DevicePathNode;
+    DevicePathNode      = NextDevicePathNode (DevicePathNode);
+  }
+
+  if (LastDevicePathNode != NULL) {
+    if (DevicePathType (LastDevicePathNode) == MEDIA_DEVICE_PATH &&
+        DevicePathSubType (LastDevicePathNode) == MEDIA_HARDDRIVE_DP
+        ) {
+      CopyMem (&ParentHdDev, LastDevicePathNode, sizeof (ParentHdDev));
+    } else {
+      LastDevicePathNode = NULL;
+    }
+  }
+
+  PartitionNumber = 1;
+
+  ZeroMem (&HdDev, sizeof (HdDev));
+  HdDev.Header.Type     = MEDIA_DEVICE_PATH;
+  HdDev.Header.SubType  = MEDIA_HARDDRIVE_DP;
+  SetDevicePathNodeLength (&HdDev.Header, sizeof (HdDev));
+  HdDev.MBRType         = MBR_TYPE_PCAT;
+  HdDev.SignatureType   = SIGNATURE_TYPE_MBR;
+
+  if (LastDevicePathNode == NULL) {
+    //
+    // This is a MBR, add each partition
+    //
+    for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
+      if (Mbr->Partition[Index].OSIndicator == 0x00 || UNPACK_UINT32 (Mbr->Partition[Index].SizeInLBA) == 0) {
+        //
+        // Don't use null MBR entries
+        //
+        continue;
+      }
+
+      if (Mbr->Partition[Index].OSIndicator == PMBR_GPT_PARTITION) {
+        //
+        // This is the guard MBR for the GPT. If you ever see a GPT disk with zero partitions you can get here.
+        //  We can not produce an MBR BlockIo for this device as the MBR spans the GPT headers. So formating
+        //  this BlockIo would corrupt the GPT structures and require a recovery that would corrupt the format
+        //  that corrupted the GPT partition.
+        //
+        continue;
+      }
+
+      HdDev.PartitionNumber = PartitionNumber ++;
+      HdDev.PartitionStart  = UNPACK_UINT32 (Mbr->Partition[Index].StartingLBA);
+      HdDev.PartitionSize   = UNPACK_UINT32 (Mbr->Partition[Index].SizeInLBA);
+      CopyMem (HdDev.Signature, &(Mbr->UniqueMbrSignature[0]), sizeof (Mbr->UniqueMbrSignature));
+
+      Status = PartitionInstallChildHandle (
+                This,
+                Handle,
+                DiskIo,
+                BlockIo,
+                BlockIo2,
+                DevicePath,
+                (EFI_DEVICE_PATH_PROTOCOL *) &HdDev,
+                HdDev.PartitionStart,
+                HdDev.PartitionStart + HdDev.PartitionSize - 1,
+                MBR_SIZE,
+                (BOOLEAN) (Mbr->Partition[Index].OSIndicator == EFI_PARTITION)
+                );
+
+      if (!EFI_ERROR (Status)) {
+        Found = EFI_SUCCESS;
+      }
+    }
+  } else {
+    //
+    // It's an extended partition. Follow the extended partition
+    // chain to get all the logical drives
+    //
+    ExtMbrStartingLba = 0;
+
+    do {
+
+      Status = DiskIo->ReadDisk (
+                         DiskIo,
+                         MediaId,
+                         MultU64x32 (ExtMbrStartingLba, BlockSize),
+                         BlockSize,
+                         Mbr
+                         );
+      if (EFI_ERROR (Status)) {
+        Found = Status;
+        goto Done;
+      }
+
+      if (UNPACK_UINT32 (Mbr->Partition[0].SizeInLBA) == 0) {
+        break;
+      }
+
+      if ((Mbr->Partition[0].OSIndicator == EXTENDED_DOS_PARTITION) ||
+          (Mbr->Partition[0].OSIndicator == EXTENDED_WINDOWS_PARTITION)) {
+        ExtMbrStartingLba = UNPACK_UINT32 (Mbr->Partition[0].StartingLBA);
+        continue;
+      }
+      HdDev.PartitionNumber = PartitionNumber ++;
+      HdDev.PartitionStart  = UNPACK_UINT32 (Mbr->Partition[0].StartingLBA) + ExtMbrStartingLba + ParentHdDev.PartitionStart;
+      HdDev.PartitionSize   = UNPACK_UINT32 (Mbr->Partition[0].SizeInLBA);
+      if ((HdDev.PartitionStart + HdDev.PartitionSize - 1 >= ParentHdDev.PartitionStart + ParentHdDev.PartitionSize) ||
+          (HdDev.PartitionStart <= ParentHdDev.PartitionStart)) {
+        break;
+      }
+
+      //
+      // The signature in EBR(Extended Boot Record) should always be 0.
+      //
+      *((UINT32 *) &HdDev.Signature[0]) = 0;
+
+      Status = PartitionInstallChildHandle (
+                 This,
+                 Handle,
+                 DiskIo,
+                 BlockIo,
+                 BlockIo2,
+                 DevicePath,
+                 (EFI_DEVICE_PATH_PROTOCOL *) &HdDev,
+                 HdDev.PartitionStart - ParentHdDev.PartitionStart,
+                 HdDev.PartitionStart - ParentHdDev.PartitionStart + HdDev.PartitionSize - 1,
+                 MBR_SIZE,
+                 (BOOLEAN) (Mbr->Partition[0].OSIndicator == EFI_PARTITION)
+                 );
+      if (!EFI_ERROR (Status)) {
+        Found = EFI_SUCCESS;
+      }
+
+      if ((Mbr->Partition[1].OSIndicator != EXTENDED_DOS_PARTITION) &&
+          (Mbr->Partition[1].OSIndicator != EXTENDED_WINDOWS_PARTITION)
+          ) {
+        break;
+      }
+
+      ExtMbrStartingLba = UNPACK_UINT32 (Mbr->Partition[1].StartingLBA);
+      //
+      // Don't allow partition to be self referencing
+      //
+      if (ExtMbrStartingLba == 0) {
+        break;
+      }
+    } while (ExtMbrStartingLba  < ParentHdDev.PartitionSize);
+  }
+
+Done:
+  FreePool (Mbr);
+
+  return Found;
+}
Index: /trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/PartitionDxe/Partition.c
===================================================================
--- /trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/PartitionDxe/Partition.c	(revision 42653)
+++ /trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/PartitionDxe/Partition.c	(revision 42653)
@@ -0,0 +1,1239 @@
+/* $Id$ */
+/** @file
+ * Partition.c
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/** @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
+  MBR, and GPT partition schemes are supported.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+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.
+
+**/
+
+
+#include "Partition.h"
+
+//
+// Partition Driver Global Variables.
+//
+EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding = {
+  PartitionDriverBindingSupported,
+  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
+  // 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
+  // gets run before that of Fat driver so that all the partitions can be recognized.
+  //
+  0xb,
+  NULL,
+  NULL
+};
+
+//
+// Prioritized function list to detect partition table.
+//
+PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable[] = {
+  PartitionInstallAppleChildHandles,
+  PartitionInstallGptChildHandles,
+  PartitionInstallElToritoChildHandles,
+  PartitionInstallMbrChildHandles,
+  NULL
+};
+
+/**
+  Test to see if this driver supports ControllerHandle. Any ControllerHandle
+  than contains a BlockIo and DiskIo protocol or a BlockIo2 protocol can be
+  supported.
+
+  @param[in]  This                Protocol instance pointer.
+  @param[in]  ControllerHandle    Handle of device to test.
+  @param[in]  RemainingDevicePath Optional parameter use to pick a specific child
+                                  device to start.
+
+  @retval EFI_SUCCESS         This driver supports this device
+  @retval EFI_ALREADY_STARTED This driver is already running on this device
+  @retval other               This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionDriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
+  )
+{
+  EFI_STATUS                Status;
+  EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;
+  EFI_DISK_IO_PROTOCOL      *DiskIo;
+  EFI_DEV_PATH              *Node;
+  LogFlowFuncEnter();
+
+  //
+  // Check RemainingDevicePath validation
+  //
+  if (RemainingDevicePath != NULL) {
+    //
+    // Check if RemainingDevicePath is the End of Device Path Node,
+    // if yes, go on checking other conditions
+    //
+    LogFlowFuncMarkDP(RemainingDevicePath);
+    if (!IsDevicePathEnd (RemainingDevicePath)) {
+      //
+      // If RemainingDevicePath isn't the End of Device Path Node,
+      // check its validation
+      //
+      Node = (EFI_DEV_PATH *) RemainingDevicePath;
+      if (     Node->DevPath.Type != MEDIA_DEVICE_PATH
+            || Node->DevPath.SubType != MEDIA_HARDDRIVE_DP
+            || DevicePathNodeLength (&Node->DevPath) != sizeof (HARDDRIVE_DEVICE_PATH)
+            || Node->DevPath.Type != MESSAGING_DEVICE_PATH
+            || Node->DevPath.SubType != MSG_SATA_DP) {
+        LogFlowFuncLeaveRC(EFI_UNSUPPORTED);
+        return EFI_UNSUPPORTED;
+      }
+    }
+  }
+
+  //
+  // Open the IO Abstraction(s) needed to perform the supported test
+  //
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiDiskIoProtocolGuid,
+                  (VOID **) &DiskIo,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (Status == EFI_ALREADY_STARTED) {
+    LogFlowFuncLeaveRC(EFI_SUCCESS);
+    return EFI_SUCCESS;
+  }
+  if (EFI_ERROR (Status)) {
+    LogFlowFuncLeaveRC(Status);
+    return Status;
+  }
+  //
+  // Close the I/O Abstraction(s) used to perform the supported test
+  //
+  gBS->CloseProtocol (
+         ControllerHandle,
+         &gEfiDiskIoProtocolGuid,
+         This->DriverBindingHandle,
+         ControllerHandle
+         );
+
+  //
+  // Open the EFI Device Path protocol needed to perform the supported test
+  //
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiDevicePathProtocolGuid,
+                  (VOID **) &ParentDevicePath,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  LogFlowFuncMarkDP(ParentDevicePath);
+  if (Status == EFI_ALREADY_STARTED) {
+    LogFlowFuncLeaveRC(EFI_SUCCESS);
+    return EFI_SUCCESS;
+  }
+
+  if (EFI_ERROR (Status)) {
+    LogFlowFuncLeaveRC(Status);
+    return Status;
+  }
+
+  //
+  // Close protocol, don't use device path protocol in the Support() function
+  //
+  gBS->CloseProtocol (
+        ControllerHandle,
+        &gEfiDevicePathProtocolGuid,
+        This->DriverBindingHandle,
+        ControllerHandle
+        );
+
+  //
+  // Open the IO Abstraction(s) needed to perform the supported test
+  //
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiBlockIoProtocolGuid,
+                  NULL,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    LogFlowFuncLeaveRC(Status);
+    return Status;
+  }
+
+  LogFlowFuncLeaveRC(EFI_SUCCESS);
+  return EFI_SUCCESS;
+}
+
+/**
+  Start this driver on ControllerHandle by opening a Block IO or a Block IO2
+  or both, and Disk IO protocol, reading Device Path, and creating a child
+  handle with a Disk IO and device path protocol.
+
+  @param[in]  This                 Protocol instance pointer.
+  @param[in]  ControllerHandle     Handle of device to bind driver to
+  @param[in]  RemainingDevicePath  Optional parameter use to pick a specific child
+                                   device to start.
+
+  @retval EFI_SUCCESS          This driver is added to ControllerHandle
+  @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle
+  @retval other                This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionDriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
+  )
+{
+  EFI_STATUS                Status;
+  EFI_STATUS                OpenStatus;
+  EFI_BLOCK_IO_PROTOCOL     *BlockIo;
+  EFI_BLOCK_IO2_PROTOCOL    *BlockIo2;
+  EFI_DISK_IO_PROTOCOL      *DiskIo;
+  EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;
+  PARTITION_DETECT_ROUTINE  *Routine;
+  BOOLEAN                   MediaPresent;
+  EFI_TPL                   OldTpl;
+  int                       idxRoutine = 0;
+
+  LogFlowFuncEnter();
+  BlockIo2 = NULL;
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+  //
+  // Check RemainingDevicePath validation
+  //
+  if (RemainingDevicePath != NULL) {
+    //
+    // Check if RemainingDevicePath is the End of Device Path Node,
+    // if yes, return EFI_SUCCESS
+    //
+    if (IsDevicePathEnd (RemainingDevicePath)) {
+      Status = EFI_SUCCESS;
+      goto Exit;
+    }
+  }
+
+  //
+  // Try to open BlockIO and BlockIO2. If BlockIO would be opened, continue,
+  // otherwise, return error.
+  //
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiBlockIoProtocolGuid,
+                  (VOID **) &BlockIo,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    LogFlowFuncMarkRC(Status);
+    goto Exit;
+  }
+
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiBlockIo2ProtocolGuid,
+                  (VOID **) &BlockIo2,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+
+  //
+  // Get the Device Path Protocol on ControllerHandle's handle.
+  //
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiDevicePathProtocolGuid,
+                  (VOID **) &ParentDevicePath,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
+    LogFlowFuncMarkRC(Status);
+    goto Exit;
+  }
+
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiDiskIoProtocolGuid,
+                  (VOID **) &DiskIo,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
+    gBS->CloseProtocol (
+          ControllerHandle,
+          &gEfiDevicePathProtocolGuid,
+          This->DriverBindingHandle,
+          ControllerHandle
+          );
+    LogFlowFuncMarkRC(Status);
+    goto Exit;
+  }
+
+  OpenStatus = Status;
+
+  //
+  // Try to read blocks when there's media or it is removable physical partition.
+  //
+  Status       = EFI_UNSUPPORTED;
+  MediaPresent = BlockIo->Media->MediaPresent;
+  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.
+    //
+    Routine = &mPartitionDetectRoutineTable[0];
+    while (*Routine != NULL) {
+      Status = (*Routine) (
+                   This,
+                   ControllerHandle,
+                   DiskIo,
+                   BlockIo,
+                   BlockIo2,
+                   ParentDevicePath
+                   );
+      LogFlowFuncMarkRC(Status);
+      if (!EFI_ERROR (Status) || Status == EFI_MEDIA_CHANGED || Status == EFI_NO_MEDIA) {
+        LogFlowFuncMarkVar(idxRoutine, "%d");
+        break;
+      }
+      Routine++;
+      idxRoutine++;
+    }
+  }
+  //
+  // In the case that the driver is already started (OpenStatus == EFI_ALREADY_STARTED),
+  // the DevicePathProtocol and the DiskIoProtocol are not actually opened by the
+  // 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
+  // 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.
+  //
+  if (EFI_ERROR (Status)          &&
+      !EFI_ERROR (OpenStatus)     &&
+      Status != EFI_MEDIA_CHANGED &&
+      !(MediaPresent && Status == EFI_NO_MEDIA)) {
+    gBS->CloseProtocol (
+          ControllerHandle,
+          &gEfiDiskIoProtocolGuid,
+          This->DriverBindingHandle,
+          ControllerHandle
+          );
+    //
+    // Close Parent BlockIO2 if has.
+    //
+    gBS->CloseProtocol (
+           ControllerHandle,
+           &gEfiBlockIo2ProtocolGuid,
+           This->DriverBindingHandle,
+           ControllerHandle
+           );
+
+    gBS->CloseProtocol (
+          ControllerHandle,
+          &gEfiDevicePathProtocolGuid,
+          This->DriverBindingHandle,
+          ControllerHandle
+          );
+  }
+
+Exit:
+  gBS->RestoreTPL (OldTpl);
+  LogFlowFuncLeaveRC(Status);
+  return Status;
+}
+
+/**
+  Stop this driver on ControllerHandle. Support stopping any child handles
+  created by this driver.
+
+  @param  This              Protocol instance pointer.
+  @param  ControllerHandle  Handle of device to stop driver on
+  @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
+                            children is zero stop the entire bus driver.
+  @param  ChildHandleBuffer List of Child Handles to Stop.
+
+  @retval EFI_SUCCESS       This driver is removed ControllerHandle
+  @retval other             This driver was not removed from this device
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionDriverBindingStop (
+  IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
+  IN  EFI_HANDLE                    ControllerHandle,
+  IN  UINTN                         NumberOfChildren,
+  IN  EFI_HANDLE                    *ChildHandleBuffer
+  )
+{
+  EFI_STATUS              Status;
+  UINTN                   Index;
+  EFI_BLOCK_IO_PROTOCOL   *BlockIo;
+  EFI_BLOCK_IO2_PROTOCOL  *BlockIo2;
+  BOOLEAN                 AllChildrenStopped;
+  PARTITION_PRIVATE_DATA  *Private;
+  EFI_DISK_IO_PROTOCOL    *DiskIo;
+
+  BlockIo  = NULL;
+  BlockIo2 = NULL;
+  Private = NULL;
+
+  if (NumberOfChildren == 0) {
+    //
+    // Close the bus driver
+    //
+    gBS->CloseProtocol (
+          ControllerHandle,
+          &gEfiDiskIoProtocolGuid,
+          This->DriverBindingHandle,
+          ControllerHandle
+          );
+    //
+    // Close Parent BlockIO2 if has.
+    //
+    gBS->CloseProtocol (
+           ControllerHandle,
+           &gEfiBlockIo2ProtocolGuid,
+           This->DriverBindingHandle,
+           ControllerHandle
+           );
+
+    gBS->CloseProtocol (
+          ControllerHandle,
+          &gEfiDevicePathProtocolGuid,
+          This->DriverBindingHandle,
+          ControllerHandle
+          );
+    return EFI_SUCCESS;
+  }
+
+  AllChildrenStopped = TRUE;
+  for (Index = 0; Index < NumberOfChildren; Index++) {
+    gBS->OpenProtocol (
+           ChildHandleBuffer[Index],
+           &gEfiBlockIoProtocolGuid,
+           (VOID **) &BlockIo,
+           This->DriverBindingHandle,
+           ControllerHandle,
+           EFI_OPEN_PROTOCOL_GET_PROTOCOL
+           );
+    //
+    // Try to locate BlockIo2.
+    //
+    gBS->OpenProtocol (
+           ChildHandleBuffer[Index],
+           &gEfiBlockIo2ProtocolGuid,
+           (VOID **) &BlockIo2,
+           This->DriverBindingHandle,
+           ControllerHandle,
+           EFI_OPEN_PROTOCOL_GET_PROTOCOL
+           );
+
+
+    Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo);
+
+    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
+                       );
+    } else {
+      BlockIo->FlushBlocks (BlockIo);
+      Status = gBS->UninstallMultipleProtocolInterfaces (
+                       ChildHandleBuffer[Index],
+                       &gEfiDevicePathProtocolGuid,
+                       Private->DevicePath,
+                       &gEfiBlockIoProtocolGuid,
+                       &Private->BlockIo,
+                       Private->EspGuid,
+                       NULL,
+                       NULL
+                       );
+    }
+
+    if (EFI_ERROR (Status)) {
+      gBS->OpenProtocol (
+             ControllerHandle,
+             &gEfiDiskIoProtocolGuid,
+             (VOID **) &DiskIo,
+             This->DriverBindingHandle,
+             ChildHandleBuffer[Index],
+             EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+             );
+    } else {
+      FreePool (Private->DevicePath);
+      FreePool (Private);
+    }
+
+    if (EFI_ERROR (Status)) {
+      AllChildrenStopped = FALSE;
+    }
+  }
+
+  if (!AllChildrenStopped) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Reset the Block Device.
+
+  @param  This                 Protocol instance pointer.
+  @param  ExtendedVerification Driver may perform diagnostics on reset.
+
+  @retval EFI_SUCCESS          The device was reset.
+  @retval EFI_DEVICE_ERROR     The device is not functioning properly and could
+                               not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionReset (
+  IN EFI_BLOCK_IO_PROTOCOL  *This,
+  IN BOOLEAN                ExtendedVerification
+  )
+{
+  PARTITION_PRIVATE_DATA  *Private;
+
+  Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
+
+  return Private->ParentBlockIo->Reset (
+                                  Private->ParentBlockIo,
+                                  ExtendedVerification
+                                  );
+}
+
+/**
+  Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED
+  for no media or media change case. Otherwise DefaultStatus is returned.
+
+  @param DiskIo             Pointer to the DiskIo instance.
+  @param MediaId            Id of the media, changes every time the media is replaced.
+  @param DefaultStatus      The default status to return when it's not the no media
+                            or media change case.
+
+  @retval EFI_NO_MEDIA      There is no media.
+  @retval EFI_MEDIA_CHANGED The media was changed.
+  @retval others            The default status to return.
+**/
+EFI_STATUS
+ProbeMediaStatus (
+  IN EFI_DISK_IO_PROTOCOL    *DiskIo,
+  IN UINT32                  MediaId,
+  IN EFI_STATUS              DefaultStatus
+  )
+{
+  EFI_STATUS                 Status;
+
+  //
+  // Read 1 byte from offset 0 but passing NULL as buffer pointer
+  //
+  Status = DiskIo->ReadDisk (DiskIo, MediaId, 0, 1, NULL);
+  if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {
+    return Status;
+  }
+  return DefaultStatus;
+}
+
+/**
+  Read by using the Disk IO protocol on the parent device. Lba addresses
+  must be converted to byte offsets.
+
+  @param  This       Protocol instance pointer.
+  @param  MediaId    Id of the media, changes every time the media is replaced.
+  @param  Lba        The starting Logical Block Address to read from
+  @param  BufferSize Size of Buffer, must be a multiple of device block size.
+  @param  Buffer     Buffer containing read data
+
+  @retval EFI_SUCCESS           The data was read correctly from the device.
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.
+  @retval EFI_NO_MEDIA          There is no media in the device.
+  @retval EFI_MEDIA_CHANGED     The MediaId does not matched the current device.
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
+  @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
+                                valid for the device.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionReadBlocks (
+  IN EFI_BLOCK_IO_PROTOCOL  *This,
+  IN UINT32                 MediaId,
+  IN EFI_LBA                Lba,
+  IN UINTN                  BufferSize,
+  OUT VOID                  *Buffer
+  )
+{
+  PARTITION_PRIVATE_DATA  *Private;
+  UINT64                  Offset;
+
+  Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
+
+  if (BufferSize % Private->BlockSize != 0) {
+    return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE);
+  }
+
+  Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
+  if (Offset + BufferSize > Private->End) {
+    return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER);
+  }
+  //
+  // Because some kinds of partition have different block size from their parent
+  // device, we call the Disk IO protocol on the parent device, not the Block IO
+  // protocol
+  //
+  return Private->DiskIo->ReadDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer);
+}
+
+/**
+  Write by using the Disk IO protocol on the parent device. Lba addresses
+  must be converted to byte offsets.
+
+  @param[in]  This       Protocol instance pointer.
+  @param[in]  MediaId    Id of the media, changes every time the media is replaced.
+  @param[in]  Lba        The starting Logical Block Address to read from
+  @param[in]  BufferSize Size of Buffer, must be a multiple of device block size.
+  @param[in]  Buffer     Buffer containing data to be written to device.
+
+  @retval EFI_SUCCESS           The data was written correctly to the device.
+  @retval EFI_WRITE_PROTECTED   The device can not be written to.
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
+  @retval EFI_NO_MEDIA          There is no media in the device.
+  @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
+  @retval EFI_INVALID_PARAMETER The write request contains a LBA that is not
+                                valid for the device.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionWriteBlocks (
+  IN EFI_BLOCK_IO_PROTOCOL  *This,
+  IN UINT32                 MediaId,
+  IN EFI_LBA                Lba,
+  IN UINTN                  BufferSize,
+  IN VOID                  *Buffer
+  )
+{
+  PARTITION_PRIVATE_DATA  *Private;
+  UINT64                  Offset;
+
+  Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
+
+  if (BufferSize % Private->BlockSize != 0) {
+    return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE);
+  }
+
+  Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
+  if (Offset + BufferSize > Private->End) {
+    return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER);
+  }
+  //
+  // Because some kinds of partition have different block size from their parent
+  // device, we call the Disk IO protocol on the parent device, not the Block IO
+  // protocol
+  //
+  return Private->DiskIo->WriteDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer);
+}
+
+
+/**
+  Flush the parent Block Device.
+
+  @param  This              Protocol instance pointer.
+
+  @retval EFI_SUCCESS       All outstanding data was written to the device
+  @retval EFI_DEVICE_ERROR  The device reported an error while writting back the data
+  @retval EFI_NO_MEDIA      There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionFlushBlocks (
+  IN EFI_BLOCK_IO_PROTOCOL  *This
+  )
+{
+  PARTITION_PRIVATE_DATA  *Private;
+
+  Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
+
+  return Private->ParentBlockIo->FlushBlocks (Private->ParentBlockIo);
+}
+
+/**
+  Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED
+  for no media or media change case. Otherwise DefaultStatus is returned.
+
+  @param BlockIo2           Pointer to the BlockIo2 instance.
+  @param MediaId            Id of the media, changes every time the media is replaced.
+  @param DefaultStatus      The default status to return when it's not the no media
+                            or media change case.
+
+  @retval EFI_NO_MEDIA      There is no media.
+  @retval EFI_MEDIA_CHANGED The media was changed.
+  @retval others            The default status to return.
+**/
+EFI_STATUS
+ProbeMediaStatusEx (
+  IN EFI_BLOCK_IO2_PROTOCOL  *BlockIo2,
+  IN UINT32                  MediaId,
+  IN EFI_STATUS              DefaultStatus
+  )
+{
+  EFI_STATUS                 Status;
+
+  //
+  // Read from LBA 0 but passing NULL as buffer pointer to detect the media status.
+  //
+  Status = BlockIo2->ReadBlocksEx (
+                       BlockIo2,
+                       MediaId,
+                       0,
+                       NULL,
+                       0,
+                       NULL
+                       );
+  if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {
+    return Status;
+  }
+  return DefaultStatus;
+}
+
+/**
+  Reset the Block Device throught Block I/O2 protocol.
+
+  @param  This                 Protocol instance pointer.
+  @param  ExtendedVerification Driver may perform diagnostics on reset.
+
+  @retval EFI_SUCCESS          The device was reset.
+  @retval EFI_DEVICE_ERROR     The device is not functioning properly and could
+                               not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionResetEx (
+  IN EFI_BLOCK_IO2_PROTOCOL *This,
+  IN BOOLEAN                ExtendedVerification
+  )
+{
+  PARTITION_PRIVATE_DATA  *Private;
+
+  Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
+
+  return Private->ParentBlockIo2->Reset (
+                                    Private->ParentBlockIo2,
+                                    ExtendedVerification
+                                    );
+}
+
+/**
+  Read BufferSize bytes from Lba into Buffer.
+
+  This function reads the requested number of blocks from the device. All the
+  blocks are read, or an error is returned.
+  If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and
+  non-blocking I/O is being used, the Event associated with this request will
+  not be signaled.
+
+  @param[in]       This       Indicates a pointer to the calling context.
+  @param[in]       MediaId    Id of the media, changes every time the media is
+                              replaced.
+  @param[in]       Lba        The starting Logical Block Address to read from.
+  @param[in, out]  Token	    A pointer to the token associated with the transaction.
+  @param[in]       BufferSize Size of Buffer, must be a multiple of device block size.
+  @param[out]      Buffer     A pointer to the destination buffer for the data. The
+                              caller is responsible for either having implicit or
+                              explicit ownership of the buffer.
+
+  @retval EFI_SUCCESS           The read request was queued if Token->Event is
+                                not NULL.The data was read correctly from the
+                                device if the Token->Event is NULL.
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing
+                                the read.
+  @retval EFI_NO_MEDIA          There is no media in the device.
+  @retval EFI_MEDIA_CHANGED     The MediaId is not for the current media.
+  @retval EFI_BAD_BUFFER_SIZE   The BufferSize parameter is not a multiple of the
+                                intrinsic block size of the device.
+  @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+                                or the buffer is not on proper alignment.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack
+                                of resources.
+**/
+EFI_STATUS
+EFIAPI
+PartitionReadBlocksEx (
+  IN     EFI_BLOCK_IO2_PROTOCOL *This,
+  IN     UINT32                 MediaId,
+  IN     EFI_LBA                Lba,
+  IN OUT EFI_BLOCK_IO2_TOKEN    *Token,
+  IN     UINTN                  BufferSize,
+  OUT    VOID                   *Buffer
+  )
+{
+  PARTITION_PRIVATE_DATA  *Private;
+  UINT64                  Offset;
+  UINT32                  UnderRun;
+
+  Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
+
+  if (Token == NULL) {
+    return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_INVALID_PARAMETER);
+  }
+
+  if (BufferSize % Private->BlockSize != 0) {
+    return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_BAD_BUFFER_SIZE);
+  }
+
+  Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
+  if (Offset + BufferSize > Private->End) {
+    return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_INVALID_PARAMETER);
+  }
+
+  //
+  // Since the BlockIO2 call Parent BlockIO2 directly, so here the offset must
+  // be multiple of BlockSize. If the Spec will be updated the DiskIO to support
+  // BlockIO2, this limitation will be removed and call DiskIO here.
+  //
+  Lba = DivU64x32Remainder (Offset, Private->BlockSize, &UnderRun);
+  if (UnderRun != 0) {
+    return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_UNSUPPORTED);
+  }
+
+  //
+  // Because some partitions have different block size from their parent
+  // device, in that case the Block I/O2 couldn't be called.
+  //
+  if (Private->BlockSize != Private->ParentBlockIo->Media->BlockSize) {
+    return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_UNSUPPORTED);
+  }
+
+  return Private->ParentBlockIo2->ReadBlocksEx (Private->ParentBlockIo2, MediaId, Lba, Token, BufferSize, Buffer);
+}
+
+/**
+  Write BufferSize bytes from Lba into Buffer.
+
+  This function writes the requested number of blocks to the device. All blocks
+  are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
+  EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
+  being used, the Event associated with this request will not be signaled.
+
+  @param[in]       This       Indicates a pointer to the calling context.
+  @param[in]       MediaId    The media ID that the write request is for.
+  @param[in]       Lba        The starting logical block address to be written. The
+                              caller is responsible for writing to only legitimate
+                              locations.
+  @param[in, out]  Token      A pointer to the token associated with the transaction.
+  @param[in]       BufferSize Size of Buffer, must be a multiple of device block size.
+  @param[in]       Buffer     A pointer to the source buffer for the data.
+
+  @retval EFI_SUCCESS           The write request was queued if Event is not NULL.
+                                The data was written correctly to the device if
+                                the Event is NULL.
+  @retval EFI_WRITE_PROTECTED   The device can not be written to.
+  @retval EFI_NO_MEDIA          There is no media in the device.
+  @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
+  @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+                                or the buffer is not on proper alignment.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack
+                                of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionWriteBlocksEx (
+  IN     EFI_BLOCK_IO2_PROTOCOL *This,
+  IN     UINT32                 MediaId,
+  IN     EFI_LBA                Lba,
+  IN OUT EFI_BLOCK_IO2_TOKEN    *Token,
+  IN     UINTN                  BufferSize,
+  IN     VOID                   *Buffer
+  )
+{
+  PARTITION_PRIVATE_DATA  *Private;
+  UINT64                  Offset;
+  UINT32                  UnderRun;
+
+  Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
+
+  if (Token == NULL) {
+    return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_INVALID_PARAMETER);
+  }
+
+  if (BufferSize % Private->BlockSize != 0) {
+    return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_BAD_BUFFER_SIZE);
+  }
+
+  Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
+  if (Offset + BufferSize > Private->End) {
+    return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_INVALID_PARAMETER);
+  }
+
+  //
+  // Since the BlockIO2 call Parent BlockIO2 directly, so here the offset must
+  // be multiple of BlockSize. If the Spec will be updated the DiskIO to support
+  // BlockIO2, this limitation will be removed and call DiskIO here.
+  //
+  Lba = DivU64x32Remainder (Offset, Private->BlockSize, &UnderRun);
+  if (UnderRun != 0) {
+    return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_UNSUPPORTED);
+  }
+
+  //
+  // Because some kinds of partition have different block size from their parent,
+  // in that case it couldn't call parent Block I/O2.
+  //
+  if (Private->BlockSize != Private->ParentBlockIo->Media->BlockSize) {
+    return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_UNSUPPORTED);
+  }
+
+  return Private->ParentBlockIo2->WriteBlocksEx (Private->ParentBlockIo2, MediaId, Lba, Token, BufferSize, Buffer);
+}
+
+/**
+  Flush the Block Device.
+
+  If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED
+  is returned and non-blocking I/O is being used, the Event associated with
+  this request will not be signaled.
+
+  @param[in]      This     Indicates a pointer to the calling context.
+  @param[in, out] Token    A pointer to the token associated with the transaction
+
+  @retval EFI_SUCCESS          The flush request was queued if Event is not NULL.
+                               All outstanding data was written correctly to the
+                               device if the Event is NULL.
+  @retval EFI_DEVICE_ERROR     The device reported an error while writting back
+                               the data.
+  @retval EFI_WRITE_PROTECTED  The device cannot be written to.
+  @retval EFI_NO_MEDIA         There is no media in the device.
+  @retval EFI_MEDIA_CHANGED    The MediaId is not for the current media.
+  @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
+                               of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionFlushBlocksEx (
+  IN     EFI_BLOCK_IO2_PROTOCOL *This,
+  IN OUT EFI_BLOCK_IO2_TOKEN    *Token
+  )
+{
+  PARTITION_PRIVATE_DATA  *Private;
+
+  Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
+
+  //
+  // Because some kinds of partition have different block size from their parent,
+  // in that case it couldn't call parent Block I/O2.
+  //
+  if (Private->BlockSize != Private->ParentBlockIo->Media->BlockSize) {
+    return EFI_UNSUPPORTED;
+  }
+
+  return Private->ParentBlockIo2->FlushBlocksEx (Private->ParentBlockIo2, Token);
+}
+
+
+/**
+  Create a child handle for a logical block device that represents the
+  bytes Start to End of the Parent Block IO device.
+
+  @param[in]  This              Protocol instance pointer.
+  @param[in]  ParentHandle      Parent Handle for new child.
+  @param[in]  ParentDiskIo      Parent DiskIo interface.
+  @param[in]  ParentBlockIo     Parent BlockIo interface.
+  @param[in]  ParentBlockIo2    Parent BlockIo2 interface.
+  @param[in]  ParentDevicePath  Parent Device Path.
+  @param[in]  DevicePathNode    Child Device Path node.
+  @param[in]  Start             Start Block.
+  @param[in]  End               End Block.
+  @param[in]  BlockSize         Child block size.
+  @param[in]  InstallEspGuid    Flag to install EFI System Partition GUID on handle.
+
+  @retval EFI_SUCCESS       A child handle was added.
+  @retval other             A child handle was not added.
+
+**/
+EFI_STATUS
+PartitionInstallChildHandle (
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN  EFI_HANDLE                   ParentHandle,
+  IN  EFI_DISK_IO_PROTOCOL         *ParentDiskIo,
+  IN  EFI_BLOCK_IO_PROTOCOL        *ParentBlockIo,
+  IN  EFI_BLOCK_IO2_PROTOCOL       *ParentBlockIo2,
+  IN  EFI_DEVICE_PATH_PROTOCOL     *ParentDevicePath,
+  IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePathNode,
+  IN  EFI_LBA                      Start,
+  IN  EFI_LBA                      End,
+  IN  UINT32                       BlockSize,
+  IN  BOOLEAN                      InstallEspGuid
+  )
+{
+  EFI_STATUS              Status;
+  PARTITION_PRIVATE_DATA  *Private;
+
+  Status  = EFI_SUCCESS;
+  Private = AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA));
+  if (Private == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Private->Signature        = PARTITION_PRIVATE_DATA_SIGNATURE;
+
+  Private->Start            = MultU64x32 (Start, ParentBlockIo->Media->BlockSize);
+  Private->End              = MultU64x32 (End + 1, ParentBlockIo->Media->BlockSize);
+
+  Private->BlockSize        = BlockSize;
+  Private->ParentBlockIo    = ParentBlockIo;
+  Private->ParentBlockIo2   = ParentBlockIo2;
+  Private->DiskIo           = ParentDiskIo;
+
+  //
+  // 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));
+
+  Private->BlockIo.Reset        = PartitionReset;
+  Private->BlockIo.ReadBlocks   = PartitionReadBlocks;
+  Private->BlockIo.WriteBlocks  = PartitionWriteBlocks;
+  Private->BlockIo.FlushBlocks  = PartitionFlushBlocks;
+
+  //
+  // Set the BlockIO2 into Private Data.
+  //
+  if (Private->ParentBlockIo2 != NULL) {
+    Private->BlockIo2.Media    = &Private->Media2;
+    CopyMem (Private->BlockIo2.Media, ParentBlockIo2->Media, sizeof (EFI_BLOCK_IO_MEDIA));
+
+    Private->BlockIo2.Reset          = PartitionResetEx;
+    Private->BlockIo2.ReadBlocksEx   = PartitionReadBlocksEx;
+    Private->BlockIo2.WriteBlocksEx  = PartitionWriteBlocksEx;
+    Private->BlockIo2.FlushBlocksEx  = PartitionFlushBlocksEx;
+  }
+
+  Private->Media.IoAlign   = 0;
+  Private->Media.LogicalPartition = TRUE;
+  Private->Media.LastBlock = DivU64x32 (
+                               MultU64x32 (
+                                 End - Start + 1,
+                                 ParentBlockIo->Media->BlockSize
+                                 ),
+                                BlockSize
+                               ) - 1;
+
+  Private->Media.BlockSize = (UINT32) BlockSize;
+
+  //
+  // For BlockIO2, it should keep the same alignment with the parent BlockIO2's.
+  //
+  Private->Media2.LogicalPartition = TRUE;
+  Private->Media2.LastBlock = Private->Media.LastBlock;
+  Private->Media2.BlockSize = (UINT32) BlockSize;
+
+  //
+  // Per UEFI Spec, LowestAlignedLba, LogicalBlocksPerPhysicalBlock and OptimalTransferLengthGranularity must be 0
+  //  for logical partitions.
+  //
+  if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION2) {
+    Private->Media.LowestAlignedLba               = 0;
+    Private->Media.LogicalBlocksPerPhysicalBlock  = 0;
+    Private->Media2.LowestAlignedLba              = 0;
+    Private->Media2.LogicalBlocksPerPhysicalBlock = 0;
+    if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION3) {
+      Private->Media.OptimalTransferLengthGranularity  = 0;
+      Private->Media2.OptimalTransferLengthGranularity = 0;
+    }
+  }
+
+  Private->DevicePath     = AppendDevicePathNode (ParentDevicePath, DevicePathNode);
+
+  if (Private->DevicePath == NULL) {
+    FreePool (Private);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  if (InstallEspGuid) {
+    Private->EspGuid = &gEfiPartTypeSystemPartGuid;
+  } else {
+    //
+    // If NULL InstallMultipleProtocolInterfaces will ignore it.
+    //
+    Private->EspGuid = NULL;
+  }
+
+  //
+  // Create the new handle.
+  // BlockIO2 will be installed on the condition that the blocksize of parent BlockIO
+  // is same with the child BlockIO's. Instead of calling the DiskIO, the child BlockIO2
+  // directly call the parent BlockIO and doesn't handle the different block size issue.
+  // If SPEC will update the DiskIO to support the Non-Blocking model, the BlockIO2 will call
+  // DiskIO to handle the blocksize unequal issue and the limitation will be remove from
+  // here.
+  //
+  Private->Handle = NULL;
+  if ((Private->ParentBlockIo2 != NULL) &&
+      (Private->ParentBlockIo2->Media->BlockSize == BlockSize)
+     ) {
+    Status = gBS->InstallMultipleProtocolInterfaces (
+                    &Private->Handle,
+                    &gEfiDevicePathProtocolGuid,
+                    Private->DevicePath,
+                    &gEfiBlockIoProtocolGuid,
+                    &Private->BlockIo,
+                    &gEfiBlockIo2ProtocolGuid,
+                    &Private->BlockIo2,
+                    Private->EspGuid,
+                    NULL,
+                    NULL
+                    );
+  } else {
+    Status = gBS->InstallMultipleProtocolInterfaces (
+                    &Private->Handle,
+                    &gEfiDevicePathProtocolGuid,
+                    Private->DevicePath,
+                    &gEfiBlockIoProtocolGuid,
+                    &Private->BlockIo,
+                    Private->EspGuid,
+                    NULL,
+                    NULL
+                    );
+  }
+
+  if (!EFI_ERROR (Status)) {
+    //
+    // Open the Parent Handle for the child
+    //
+    Status = gBS->OpenProtocol (
+                    ParentHandle,
+                    &gEfiDiskIoProtocolGuid,
+                    (VOID **) &ParentDiskIo,
+                    This->DriverBindingHandle,
+                    Private->Handle,
+                    EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+                    );
+  } else {
+    FreePool (Private->DevicePath);
+    FreePool (Private);
+  }
+
+  return Status;
+}
+
+
+/**
+  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] 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.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializePartition (
+  IN EFI_HANDLE           ImageHandle,
+  IN EFI_SYSTEM_TABLE     *SystemTable
+  )
+{
+  EFI_STATUS              Status;
+
+  //
+  // Install driver model protocol(s).
+  //
+  Status = EfiLibInstallDriverBindingComponentName2 (
+             ImageHandle,
+             SystemTable,
+             &gPartitionDriverBinding,
+             ImageHandle,
+             &gPartitionComponentName,
+             &gPartitionComponentName2
+             );
+  ASSERT_EFI_ERROR (Status);
+
+
+  return Status;
+}
+
Index: /trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/PartitionDxe/Partition.h
===================================================================
--- /trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/PartitionDxe/Partition.h	(revision 42653)
+++ /trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/PartitionDxe/Partition.h	(revision 42653)
@@ -0,0 +1,470 @@
+/* $Id$ */
+/** @file
+ * Partition.h
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/** @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
+  MBR, and GPT partition schemes are supported.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+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.
+
+**/
+
+#ifndef _PARTITION_H_
+#define _PARTITION_H_
+
+#include <Uefi.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/BlockIo2.h>
+#include <Guid/Gpt.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/DiskIo.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+
+#include <IndustryStandard/Mbr.h>
+#include <IndustryStandard/ElTorito.h>
+
+
+//
+// Partition private data
+//
+#define PARTITION_PRIVATE_DATA_SIGNATURE  SIGNATURE_32 ('P', 'a', 'r', 't')
+typedef struct {
+  UINT64                    Signature;
+
+  EFI_HANDLE                Handle;
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
+  EFI_BLOCK_IO_PROTOCOL     BlockIo;
+  EFI_BLOCK_IO2_PROTOCOL    BlockIo2;
+  EFI_BLOCK_IO_MEDIA        Media;
+  EFI_BLOCK_IO_MEDIA        Media2;//For BlockIO2
+
+  EFI_DISK_IO_PROTOCOL      *DiskIo;
+  EFI_BLOCK_IO_PROTOCOL     *ParentBlockIo;
+  EFI_BLOCK_IO2_PROTOCOL    *ParentBlockIo2;
+  UINT64                    Start;
+  UINT64                    End;
+  UINT32                    BlockSize;
+
+  EFI_GUID                  *EspGuid;
+
+} PARTITION_PRIVATE_DATA;
+
+#define PARTITION_DEVICE_FROM_BLOCK_IO_THIS(a)  CR (a, PARTITION_PRIVATE_DATA, BlockIo, PARTITION_PRIVATE_DATA_SIGNATURE)
+#define PARTITION_DEVICE_FROM_BLOCK_IO2_THIS(a) CR (a, PARTITION_PRIVATE_DATA, BlockIo2, PARTITION_PRIVATE_DATA_SIGNATURE)
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL   gPartitionDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL   gPartitionComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL  gPartitionComponentName2;
+
+//
+// Extract INT32 from char array
+//
+#define UNPACK_INT32(a) (INT32)( (((UINT8 *) a)[0] <<  0) |    \
+                                 (((UINT8 *) a)[1] <<  8) |    \
+                                 (((UINT8 *) a)[2] << 16) |    \
+                                 (((UINT8 *) a)[3] << 24) )
+
+//
+// Extract UINT32 from char array
+//
+#define UNPACK_UINT32(a) (UINT32)( (((UINT8 *) a)[0] <<  0) |    \
+                                   (((UINT8 *) a)[1] <<  8) |    \
+                                   (((UINT8 *) a)[2] << 16) |    \
+                                   (((UINT8 *) a)[3] << 24) )
+
+
+//
+// GPT Partition Entry Status
+//
+typedef struct {
+  BOOLEAN OutOfRange;
+  BOOLEAN Overlap;
+  BOOLEAN OsSpecific;
+} EFI_PARTITION_ENTRY_STATUS;
+
+//
+// Function Prototypes
+//
+/**
+  Test to see if this driver supports ControllerHandle. Any ControllerHandle
+  than contains a BlockIo and DiskIo protocol can be supported.
+
+  @param  This                Protocol instance pointer.
+  @param  ControllerHandle    Handle of device to test
+  @param  RemainingDevicePath Optional parameter use to pick a specific child
+                              device to start.
+
+  @retval EFI_SUCCESS         This driver supports this device
+  @retval EFI_ALREADY_STARTED This driver is already running on this device
+  @retval other               This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionDriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
+  );
+
+/**
+  Start this driver on ControllerHandle by opening a Block IO and Disk IO
+  protocol, reading Device Path, and creating a child handle with a
+  Disk IO and device path protocol.
+
+  @param  This                 Protocol instance pointer.
+  @param  ControllerHandle     Handle of device to bind driver to
+  @param  RemainingDevicePath  Optional parameter use to pick a specific child
+                               device to start.
+
+  @retval EFI_SUCCESS          This driver is added to ControllerHandle
+  @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle
+  @retval other                This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionDriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
+  );
+
+/**
+  Stop this driver on ControllerHandle. Support stopping any child handles
+  created by this driver.
+
+  @param  This              Protocol instance pointer.
+  @param  ControllerHandle  Handle of device to stop driver on
+  @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
+                            children is zero stop the entire bus driver.
+  @param  ChildHandleBuffer List of Child Handles to Stop.
+
+  @retval EFI_SUCCESS       This driver is removed ControllerHandle
+  @retval other             This driver was not removed from this device
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionDriverBindingStop (
+  IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
+  IN  EFI_HANDLE                    ControllerHandle,
+  IN  UINTN                         NumberOfChildren,
+  IN  EFI_HANDLE                    *ChildHandleBuffer
+  );
+
+//
+// EFI Component Name Functions
+//
+/**
+  Retrieves a Unicode string that is the user readable name of the driver.
+
+  This function retrieves the user readable name of a driver in the form of a
+  Unicode string. If the driver specified by This has a user readable name in
+  the language specified by Language, then a pointer to the driver name is
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+  by This does not support the language specified by Language,
+  then EFI_UNSUPPORTED is returned.
+
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  Language[in]          A pointer to a Null-terminated ASCII string
+                                array indicating the language. This is the
+                                language of the driver name that the caller is
+                                requesting, and it must match one of the
+                                languages specified in SupportedLanguages. The
+                                number of languages supported by a driver is up
+                                to the driver writer. Language is specified
+                                in RFC 4646 or ISO 639-2 language code format.
+
+  @param  DriverName[out]       A pointer to the Unicode string to return.
+                                This Unicode string is the name of the
+                                driver specified by This in the language
+                                specified by Language.
+
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by
+                                This and the language specified by Language was
+                                returned in DriverName.
+
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support
+                                the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionComponentNameGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  CHAR8                        *Language,
+  OUT CHAR16                       **DriverName
+  );
+
+
+/**
+  Retrieves a Unicode string that is the user readable name of the controller
+  that is being managed by a driver.
+
+  This function retrieves the user readable name of the controller specified by
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the
+  driver specified by This has a user readable name in the language specified by
+  Language, then a pointer to the controller name is returned in ControllerName,
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently
+  managing the controller specified by ControllerHandle and ChildHandle,
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  ControllerHandle[in]  The handle of a controller that the driver
+                                specified by This is managing.  This handle
+                                specifies the controller whose name is to be
+                                returned.
+
+  @param  ChildHandle[in]       The handle of the child controller to retrieve
+                                the name of.  This is an optional parameter that
+                                may be NULL.  It will be NULL for device
+                                drivers.  It will also be NULL for a bus drivers
+                                that wish to retrieve the name of the bus
+                                controller.  It will not be NULL for a bus
+                                driver that wishes to retrieve the name of a
+                                child controller.
+
+  @param  Language[in]          A pointer to a Null-terminated ASCII string
+                                array indicating the language.  This is the
+                                language of the driver name that the caller is
+                                requesting, and it must match one of the
+                                languages specified in SupportedLanguages. The
+                                number of languages supported by a driver is up
+                                to the driver writer. Language is specified in
+                                RFC 4646 or ISO 639-2 language code format.
+
+  @param  ControllerName[out]   A pointer to the Unicode string to return.
+                                This Unicode string is the name of the
+                                controller specified by ControllerHandle and
+                                ChildHandle in the language specified by
+                                Language from the point of view of the driver
+                                specified by This.
+
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in
+                                the language specified by Language for the
+                                driver specified by This was returned in
+                                DriverName.
+
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+                                EFI_HANDLE.
+
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently
+                                managing the controller specified by
+                                ControllerHandle and ChildHandle.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support
+                                the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionComponentNameGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
+  IN  EFI_HANDLE                                      ControllerHandle,
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
+  IN  CHAR8                                           *Language,
+  OUT CHAR16                                          **ControllerName
+  );
+
+
+/**
+  Create a child handle for a logical block device that represents the
+  bytes Start to End of the Parent Block IO device.
+
+  @param[in]  This              Protocol instance pointer.
+  @param[in]  ParentHandle      Parent Handle for new child.
+  @param[in]  ParentDiskIo      Parent DiskIo interface.
+  @param[in]  ParentBlockIo     Parent BlockIo interface.
+  @param[in]  ParentBlockIo2    Parent BlockIo2 interface.
+  @param[in]  ParentDevicePath  Parent Device Path.
+  @param[in]  DevicePathNode    Child Device Path node.
+  @param[in]  Start             Start Block.
+  @param[in]  End               End Block.
+  @param[in]  BlockSize         Child block size.
+  @param[in]  InstallEspGuid    Flag to install EFI System Partition GUID on handle.
+
+  @retval EFI_SUCCESS       A child handle was added.
+  @retval other             A child handle was not added.
+
+**/
+EFI_STATUS
+PartitionInstallChildHandle (
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN  EFI_HANDLE                   ParentHandle,
+  IN  EFI_DISK_IO_PROTOCOL         *ParentDiskIo,
+  IN  EFI_BLOCK_IO_PROTOCOL        *ParentBlockIo,
+  IN  EFI_BLOCK_IO2_PROTOCOL       *ParentBlockIo2,
+  IN  EFI_DEVICE_PATH_PROTOCOL     *ParentDevicePath,
+  IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePathNode,
+  IN  EFI_LBA                      Start,
+  IN  EFI_LBA                      End,
+  IN  UINT32                       BlockSize,
+  IN  BOOLEAN                      InstallEspGuid
+  );
+
+/**
+  Install child handles if the Handle supports GPT partition structure.
+
+  @param[in]  This       Calling context.
+  @param[in]  Handle     Parent Handle.
+  @param[in]  DiskIo     Parent DiskIo interface.
+  @param[in]  BlockIo    Parent BlockIo interface.
+  @param[in]  BlockIo2   Parent BlockIo2 interface.
+  @param[in]  DevicePath Parent Device Path.
+
+  @retval EFI_SUCCESS           Valid GPT disk.
+  @retval EFI_MEDIA_CHANGED     Media changed Detected.
+  @retval EFI_INVALID_PARAMETER If both BlockIo and BlockIo2 are NULL;
+  @retval other                 Not a valid GPT disk.
+
+**/
+EFI_STATUS
+PartitionInstallGptChildHandles (
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN  EFI_HANDLE                   Handle,
+  IN  EFI_DISK_IO_PROTOCOL         *DiskIo,
+  IN  EFI_BLOCK_IO_PROTOCOL        *BlockIo,
+  IN  EFI_BLOCK_IO2_PROTOCOL       *BlockIo2,
+  IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath
+  );
+
+/**
+  Install child handles if the Handle supports El Torito format.
+
+  @param[in]  This        Calling context.
+  @param[in]  Handle      Parent Handle.
+  @param[in]  DiskIo      Parent DiskIo interface.
+  @param[in]  BlockIo     Parent BlockIo interface.
+  @param[in]  BlockIo2    Parent BlockIo2 interface.
+  @param[in]  DevicePath  Parent Device Path
+
+
+  @retval EFI_SUCCESS         Child handle(s) was added.
+  @retval EFI_MEDIA_CHANGED   Media changed Detected.
+  @retval other               no child handle was added.
+
+**/
+EFI_STATUS
+PartitionInstallElToritoChildHandles (
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN  EFI_HANDLE                   Handle,
+  IN  EFI_DISK_IO_PROTOCOL         *DiskIo,
+  IN  EFI_BLOCK_IO_PROTOCOL        *BlockIo,
+  IN  EFI_BLOCK_IO2_PROTOCOL       *BlockIo2,
+  IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath
+  );
+
+/**
+  Install child handles if the Handle supports MBR format.
+
+  @param[in]  This              Calling context.
+  @param[in]  Handle            Parent Handle.
+  @param[in]  DiskIo            Parent DiskIo interface.
+  @param[in]  BlockIo           Parent BlockIo interface.
+  @param[in]  BlockIo2          Parent BlockIo2 interface.
+  @param[in]  DevicePath        Parent Device Path.
+
+  @retval EFI_SUCCESS       A child handle was added.
+  @retval EFI_MEDIA_CHANGED Media change was detected.
+  @retval Others            MBR partition was not found.
+
+**/
+EFI_STATUS
+PartitionInstallMbrChildHandles (
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN  EFI_HANDLE                   Handle,
+  IN  EFI_DISK_IO_PROTOCOL         *DiskIo,
+  IN  EFI_BLOCK_IO_PROTOCOL        *BlockIo,
+  IN  EFI_BLOCK_IO2_PROTOCOL       *BlockIo2,
+  IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath
+  );
+
+
+/**
+  Install child handles if the Handle supports Apple format.
+
+  @param  This              Calling context.
+  @param  Handle            Parent Handle.
+  @param  DiskIo            Parent DiskIo interface.
+  @param  BlockIo           Parent BlockIo interface.
+  @param[in]  BlockIo2          Parent BlockIo2 interface.
+  @param  DevicePath        Parent Device Path.
+
+  @retval EFI_SUCCESS       A child handle was added.
+  @retval EFI_MEDIA_CHANGED Media change was detected.
+  @retval Others            Apple partition was not found.
+
+**/
+EFI_STATUS
+PartitionInstallAppleChildHandles (
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN  EFI_HANDLE                   Handle,
+  IN  EFI_DISK_IO_PROTOCOL         *DiskIo,
+  IN  EFI_BLOCK_IO_PROTOCOL        *BlockIo,
+  IN  EFI_BLOCK_IO2_PROTOCOL       *BlockIo2,
+  IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath
+  );
+
+typedef
+EFI_STATUS
+(*PARTITION_DETECT_ROUTINE) (
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN  EFI_HANDLE                   Handle,
+  IN  EFI_DISK_IO_PROTOCOL         *DiskIo,
+  IN  EFI_BLOCK_IO_PROTOCOL        *BlockIo,
+  IN  EFI_BLOCK_IO2_PROTOCOL       *BlockIo2,
+  IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath
+  );
+
+#endif
