예제 #1
0
/**
  Install child handles if the Handle supports MBR format.

  @param  This              Calling context.
  @param  Handle            Parent Handle.
  @param  DiskIo            Parent DiskIo interface.
  @param  BlockIo           Parent BlockIo interface.
  @param  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_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;

  Found           = EFI_NOT_FOUND;

  Mbr             = AllocatePool (BlockIo->Media->BlockSize);
  if (Mbr == NULL) {
    return Found;
  }

  Status = DiskIo->ReadDisk (
                     DiskIo,
                     BlockIo->Media->MediaId,
                     0,
                     BlockIo->Media->BlockSize,
                     Mbr
                     );
  if (EFI_ERROR (Status)) {
    Found = Status;
    goto Done;
  }
  if (!PartitionValidMbr (Mbr, BlockIo->Media->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,
                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,
                         BlockIo->Media->MediaId,
                         MultU64x32 (ExtMbrStartingLba, BlockIo->Media->BlockSize),
                         BlockIo->Media->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,
                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;
}
예제 #2
0
/**
  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]  DiskIo2     Parent DiskIo2 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_DISK_IO2_PROTOCOL        *DiskIo2,
  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;

  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
      //
 //     DBG("ELT: end of media\n")
      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
      //
//      DBG("ELT: end of Volume descriptor list\n");
      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];
      DBG("ELT: VolSpaceSize =%d\n", VolSpaceSize); 
    }
    //
    // 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);
    DBG("ELT: this is ELT at lba=%d\n", Lba);
    if (Lba > Media->LastBlock) {
      continue;
    }

      Status = DiskIo->ReadDisk (
                       DiskIo,
                       Media->MediaId,
                       MultU64x32 (Lba, Media->BlockSize),
                       Media->BlockSize,
                       Catalog
                       );
    if (EFI_ERROR (Status)) {
      DBG ("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) {
      DBG ("EltCheckBootCatalog: El Torito boot catalog header IDs=%x not correct\n",
           Catalog->Catalog.Indicator);
      continue;
    }

    Check       = 0;
    CheckBuffer = (UINT16 *) Catalog;
    for (Index = 0; Index < sizeof (ELTORITO_CATALOG) / sizeof (UINT16); Index += 1) {
      Check += CheckBuffer[Index];
    }

    if ((Check & 0xFFFF) != 0) {
      DBG ( "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;
      DBG("ELT: SectorCount   =%d\n", SectorCount);
      switch (Catalog->Boot.MediaType) {

      case ELTORITO_NO_EMULATION:
        SubBlockSize = Media->BlockSize;
          DBG("ELT: SubBlockSize =%d\n", SubBlockSize);
        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:
        DBG("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;
        SectorCount = 0; //Slice
      }

      CdDev.BootEntry = (UINT32) BootEntry;
      BootEntry++;
      CdDev.PartitionStart = Catalog->Boot.Lba;
      DBG("ELT: Partition start %d\n", CdDev.PartitionStart);
      if (SectorCount < 2) {
        //
        // When the SectorCount < 2, set the Partition as the whole CD.
        //
        CdDev.PartitionStart = 0; //Slice
        if (VolSpaceSize > (Media->LastBlock + 1)) {
          CdDev.PartitionSize = (UINT32)(Media->LastBlock - Catalog->Boot.Lba + 1);
        } else {
          CdDev.PartitionSize = (UINT32)(VolSpaceSize - Catalog->Boot.Lba);
        }
        DBG("ELT: WholeCD PartitionSize=%d\n", CdDev.PartitionSize);
      } else {
        CdDev.PartitionSize = DivU64x32 (
                                MultU64x32 (
                                  SectorCount,
                                  SubBlockSize
                                  ) + Media->BlockSize - 1,
                                Media->BlockSize
                                );
        DBG("ELT: CD Partition%d Size=%d\n", Index, CdDev.PartitionSize);
      }

      Status = PartitionInstallChildHandle (
                This,
                Handle,
                DiskIo,
                DiskIo2,
                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;
}
예제 #3
0
파일: Apple.c 프로젝트: weixu8/Duet
/**
  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;
  UINT32                    Partition;
  UINT32                    PartitionEntries;
  UINT32                    VolSpaceSize;
  UINT32                    SubBlockSize;
  UINT32                    BlkPerSec;
  UINT32                    MediaId;
	UINT32                    BlockSize;
	EFI_LBA                   LastBlock;
  APPLE_PT_HEADER           *AppleHeader;
  APPLE_PT_ENTRY            *AppleEntry;
  UINT32                    StartLba;
  UINT32                    SizeLbs;
	

  Media         = BlockIo->Media;
  BlockSize     = BlockIo->Media->BlockSize;
  LastBlock     = BlockIo->Media->LastBlock;
  MediaId       = BlockIo->Media->MediaId;
  VolSpaceSize  = 0;

  AppleHeader = AllocatePool (BlockSize);

  if (AppleHeader == NULL) return EFI_NOT_FOUND;

  do {
      Lba = 0;
      Status = DiskIo->ReadDisk (
                       DiskIo,
                       MediaId,
                       0,
                       BlockSize,
                       AppleHeader
                       );
      if (EFI_ERROR (Status)) goto done;
//      Header = (APPLE_PT_HEADER *)Block;

      if (SwapBytes16(AppleHeader->sbSig) != 0x4552) {
        Status = EFI_NOT_FOUND;
        goto done; 
      }
      SubBlockSize = SwapBytes16(AppleHeader->sbBlkSize);
      BlkPerSec    = BlockSize / SubBlockSize;
      if (BlockSize != SubBlockSize * BlkPerSec) {
        Status = EFI_NOT_FOUND;
        goto done; 
      }
      AppleEntry = AllocatePool (SubBlockSize);
      PartitionEntries = 1;
      for (Partition = 1; Partition <= PartitionEntries; Partition++)
      {
          Status = DiskIo->ReadDisk (
                       DiskIo,
                       MediaId,
                       MultU64x32 (Partition, SubBlockSize),
                       SubBlockSize,
                       AppleEntry
                       );

          if (EFI_ERROR (Status)) {
              Status = EFI_NOT_FOUND;
              goto done; /* would break, but ... */
          }

//          Entry = (APPLE_PT_ENTRY *)Block;

          if (SwapBytes16(AppleEntry->signature) != 0x504D) continue;
          if (Partition == 1) PartitionEntries  = SwapBytes32(AppleEntry->map_entries);
          StartLba = SwapBytes32(AppleEntry->pblock_start);
          SizeLbs  = SwapBytes32(AppleEntry->pblocks);
          ZeroMem (&CdDev, sizeof (CdDev));
          CdDev.Header.Type     = MEDIA_DEVICE_PATH;
          CdDev.Header.SubType  = MEDIA_CDROM_DP;
          SetDevicePathNodeLength (&CdDev.Header, sizeof (CdDev));
          CdDev.BootEntry = 0;
          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 );
      }

  } while (0);

 done:
  
  FreePool (AppleHeader);
  FreePool (AppleEntry);

  return Status;
}
예제 #4
0
/**
  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;

  VBoxLogFlowFuncMarkDP(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;
}
예제 #5
0
파일: Apple.c 프로젝트: etiago/vbox
/**
  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;

  VBoxLogFlowFuncMarkDP(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;
}
/**
  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]  DiskIo2     Parent DiskIo2 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_DISK_IO2_PROTOCOL        *DiskIo2,
  IN  EFI_BLOCK_IO_PROTOCOL        *BlockIo,
  IN  EFI_BLOCK_IO2_PROTOCOL       *BlockIo2,
  IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath
  )
{
  EFI_STATUS              Status;
  UINT64                  VolDescriptorOffset;
  UINT32                  Lba2KB;
  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;

  Found         = EFI_NOT_FOUND;
  Media         = BlockIo->Media;

  VolSpaceSize  = 0;

  //
  // CD_ROM has the fixed block size as 2048 bytes (SIZE_2KB)
  //

  // If the ISO image has been copied onto a different storage media
  // then the block size might be different (eg: USB).
  // Ensure 2048 (SIZE_2KB) is a multiple of block size
  if (((SIZE_2KB % Media->BlockSize) != 0) || (Media->BlockSize > SIZE_2KB)) {
    return EFI_NOT_FOUND;
  }

  VolDescriptor = AllocatePool ((UINTN)SIZE_2KB);

  if (VolDescriptor == NULL) {
    return EFI_NOT_FOUND;
  }

  Catalog = (ELTORITO_CATALOG *) VolDescriptor;

  //
  // Loop: handle one volume descriptor per time
  //       The ISO-9660 volume descriptor starts at 32k on the media
  //
  for (VolDescriptorOffset = SIZE_32KB;
       VolDescriptorOffset <= MultU64x32 (Media->LastBlock, Media->BlockSize);
       VolDescriptorOffset += SIZE_2KB) {
    Status = DiskIo->ReadDisk (
                       DiskIo,
                       Media->MediaId,
                       VolDescriptorOffset,
                       SIZE_2KB,
                       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
    // The LBA unit used by El Torito boot catalog is 2KB unit
    //
    Lba2KB = UNPACK_INT32 (VolDescriptor->BootRecordVolume.EltCatalog);
    // Ensure the LBA (in 2KB unit) fits into our media
    if (Lba2KB * (SIZE_2KB / Media->BlockSize) > Media->LastBlock) {
      continue;
    }

    Status = DiskIo->ReadDisk (
                       DiskIo,
                       Media->MediaId,
                       MultU64x32 (Lba2KB, SIZE_2KB),
                       SIZE_2KB,
                       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 * (SIZE_2KB / Media->BlockSize);

      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 * (SIZE_2KB / Media->BlockSize);
      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,
                DiskIo2,
                BlockIo,
                BlockIo2,
                DevicePath,
                (EFI_DEVICE_PATH_PROTOCOL *) &CdDev,
                Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize),
                MultU64x32 (Catalog->Boot.Lba + CdDev.PartitionSize - 1, SIZE_2KB / Media->BlockSize),
                SubBlockSize,
                FALSE
                );
      if (!EFI_ERROR (Status)) {
        Found = EFI_SUCCESS;
      }
    }
  }

  FreePool (VolDescriptor);

  return Found;
}
/**
  Install child handles if the Handle supports AddLbaOfs format.

  @param[in]  This              Calling context.
  @param[in]  Handle            Parent Handle.
  @param[in]  DiskIo            Parent DiskIo interface.
  @param[in]  DiskIo2           Parent DiskIo2 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
PartitionInstallAddLbaOfsChildHandles (
  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
  IN  EFI_HANDLE                   Handle,
  IN  EFI_DISK_IO_PROTOCOL         *DiskIo,
  IN  EFI_DISK_IO2_PROTOCOL        *DiskIo2,
  IN  EFI_BLOCK_IO_PROTOCOL        *BlockIo,
  IN  EFI_BLOCK_IO2_PROTOCOL       *BlockIo2,
  IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath
  )
{
#undef FN
#define FN "PartitionInstallAddLbaOfsChildHandles"
#define DBG_PartitionInstallAddLbaOfsChildHandles DL_80 /* DL_DISABLED DL_80 */
  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;
  EFI_LBA                   AddLbaOfs;
  EFI_LBA                   Lba;


  DBG_PR(DBG_PartitionInstallAddLbaOfsChildHandles, "entered\n");

  Found           = EFI_NOT_FOUND;

  BlockSize = BlockIo->Media->BlockSize;
  MediaId   = BlockIo->Media->MediaId;
  LastBlock = BlockIo->Media->LastBlock;
  DBG_PR(DBG_PartitionInstallAddLbaOfsChildHandles, "BlockSize=%"PRIx64" MediaId=%"PRIx64" LastBlock=%"PRIx64"\n", BlockSize, MediaId, LastBlock);

  Mbr = AllocatePool (BlockSize);
  if (Mbr == NULL) {
    return Found;
  }

  for (Lba = 0; Lba < 1; Lba++) {
    Status = DiskIo->ReadDisk(
                     DiskIo,
                     MediaId,
                     Lba * BlockSize,
                     BlockSize,
                     Mbr
                     );
    DBG_PR(DBG_PartitionInstallAddLbaOfsChildHandles, "ReadDisk MediaId=%"PRIx32" Lba*BlockSize=%"PRIx64" %r\n", MediaId, Lba * BlockSize, Status);
    if (!EFI_ERROR(Status)) {
      DBG_X(DBG_PartitionInstallAddLbaOfsChildHandles, (PrBufxxdr(Mbr, BlockSize)));
      if (PartitionValidAddLbaOfs (Mbr, LastBlock)) {
        goto ValidMbr;
      }
    }

#if 0
    Status = DiskIo->ReadDisk(
                     DiskIo,
                     MediaId,
                     (LastBlock - Lba) * BlockSize,
                     BlockSize,
                     Mbr
                     );
    DBG_PR(DBG_PartitionInstallAddLbaOfsChildHandles, "ReadDisk MediaId=%"PRIx32" (LastBlock-Lba)*BlockSize=%"PRIx64" %r\n", MediaId, (LastBlock - Lba) * BlockSize, Status);
    if (!EFI_ERROR(Status)) {
      DBG_X(DBG_PartitionInstallAddLbaOfsChildHandles, (PrBufxxdr(Mbr, BlockSize)));
      if (PartitionValidAddLbaOfs (Mbr, LastBlock)) {
        goto ValidMbr;
      }
    }
#endif
  } /* for */
  goto Done;
ValidMbr:
  DBG_PR(DBG_PartitionInstallAddLbaOfsChildHandles, "ValidMbr\n");
  //
  // 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; //TBD MEDIA_VENDOR_DP
  SetDevicePathNodeLength (&HdDev.Header, sizeof (HdDev));
  HdDev.MBRType         = MBR_TYPE_PCAT; //TBD
  HdDev.SignatureType   = SIGNATURE_TYPE_GUID + 1; //TBD

  if (LastDevicePathNode == NULL) {
    //
    // This is a MBR, add each partition
    //
    Index = 0;
    /* for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) { */
      AddLbaOfs = SwapBytes64(*((UINT64 *)((UINT8 *)&Mbr->BootStrapCode[ADDLBAOFS_32_OFS])));
      DBG_PR(DBG_PartitionInstallAddLbaOfsChildHandles, "AddLbaOfs=%"PRIx64"\n", AddLbaOfs);
      
      HdDev.PartitionNumber = PartitionNumber ++;
      HdDev.PartitionStart  = AddLbaOfs; /* UNPACK_UINT32 (Mbr->Partition[Index].StartingLBA); */
      HdDev.PartitionSize   = LastBlock + 1 - AddLbaOfs; /* UNPACK_UINT32 (Mbr->Partition[Index].SizeInLBA); */
      CopyMem (HdDev.Signature, &(Mbr->UniqueMbrSignature[0]), sizeof (Mbr->UniqueMbrSignature));

      Status = PartitionInstallChildHandle (
                This,
                Handle,
                DiskIo,
                DiskIo2,
                BlockIo,
                BlockIo2,
                DevicePath,
                (EFI_DEVICE_PATH_PROTOCOL *) &HdDev,
                HdDev.PartitionStart,
                HdDev.PartitionStart + HdDev.PartitionSize - 1,
                MBR_SIZE,
                (BOOLEAN) (Mbr->Partition[Index].OSIndicator == EFI_PARTITION)
                );
      DBG_PR(DBG_PartitionInstallAddLbaOfsChildHandles, "PartitionInstallChildHandle %r\n", Status);
      if (!EFI_ERROR (Status)) {
        Found = EFI_SUCCESS;
      }
    /* } /* for */
  } else {
#if 1
    //Found = EFI_NOT_FOUND;
    goto Done;
#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,
                 DiskIo2,
                 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);
#endif
  }

Done:
  FreePool (Mbr);

  DBG_PR(DBG_PartitionInstallAddLbaOfsChildHandles, "Found=%d\n", Found);
  return Found;
}