From d6a2a8f43142b8e12eeba8936ab37de2ab1504e6 Mon Sep 17 00:00:00 2001
From: Olivier Martin <olivier.martin@arm.com>
Date: Mon, 20 Oct 2014 16:39:43 +0100
Subject: [PATCH] MdeModulePkg/PartitionDxe: Fixed El Torito support when the
 medium is not a CDROM

El Torito format can be used on different media (eg: USB).
A ISO image can be dumped onto a USB mass-storage.

These media might not have the same block size as the CDROM media (ie: 2KB).
The El Torito code and the specification assumes a LBA 2KB.

In addition, the specification says in "12.3.4.4 CD-ROM and DVD-ROM":
UEFI code does not assume a fixed block size.

I was able to dupliacte the issue by copying a debian ISO on a USB driver.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Olivier Martin <olivier.martin@arm.com>
---
 .../Universal/Disk/PartitionDxe/ElTorito.c         | 58 +++++++++++++---------
 1 file changed, 35 insertions(+), 23 deletions(-)

diff --git a/MdeModulePkg/Universal/Disk/PartitionDxe/ElTorito.c b/MdeModulePkg/Universal/Disk/PartitionDxe/ElTorito.c
index 3d7cf2d..f5aca11 100644
--- a/MdeModulePkg/Universal/Disk/PartitionDxe/ElTorito.c
+++ b/MdeModulePkg/Universal/Disk/PartitionDxe/ElTorito.c
@@ -45,8 +45,8 @@ PartitionInstallElToritoChildHandles (
   )
 {
   EFI_STATUS              Status;
-  UINT32                  VolDescriptorLba;
-  UINT32                  Lba;
+  UINT64                  VolDescriptorOffset;
+  UINT32                  Lba2KB;
   EFI_BLOCK_IO_MEDIA      *Media;
   CDROM_VOLUME_DESCRIPTOR *VolDescriptor;
   ELTORITO_CATALOG        *Catalog;
@@ -60,6 +60,7 @@ PartitionInstallElToritoChildHandles (
   UINT32                  SectorCount;
   EFI_STATUS              Found;
   UINT32                  VolSpaceSize;
+  BOOLEAN                 IsFirstVolumeDescriptor;
 
   Found         = EFI_NOT_FOUND;
   Media         = BlockIo->Media;
@@ -67,13 +68,17 @@ PartitionInstallElToritoChildHandles (
   VolSpaceSize  = 0;
 
   //
-  // CD_ROM has the fixed block size as 2048 bytes
+  // CD_ROM has the fixed block size as 2048 bytes (SIZE_2KB)
   //
-  if (Media->BlockSize != 2048) {
+
+  // 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) Media->BlockSize);
+  VolDescriptor = AllocatePool ((UINTN)SIZE_2KB);
 
   if (VolDescriptor == NULL) {
     return EFI_NOT_FOUND;
@@ -82,20 +87,25 @@ PartitionInstallElToritoChildHandles (
   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;
+  // The ISO-9660 volume descriptor starts at 32k on the media
   //
-  VolDescriptorLba = 15;
+  VolDescriptorOffset = SIZE_32KB;
+
   //
   // Loop: handle one volume descriptor per time
   //
+  IsFirstVolumeDescriptor = TRUE;
   while (TRUE) {
+    if (IsFirstVolumeDescriptor) {
+      // The volume descriptor offset is already pointed to the correct offset.
+      // We do not need to increment it.
+      IsFirstVolumeDescriptor = FALSE;
+    } else {
+      // Move to the next volume descriptor
+      VolDescriptorOffset += SIZE_2KB;
+    }
 
-    VolDescriptorLba += 1;
-    if (VolDescriptorLba > Media->LastBlock) {
+    if (VolDescriptorOffset > MultU64x32 (Media->LastBlock, Media->BlockSize)) {
       //
       // We are pointing past the end of the device so exit
       //
@@ -105,8 +115,8 @@ PartitionInstallElToritoChildHandles (
     Status = DiskIo->ReadDisk (
                        DiskIo,
                        Media->MediaId,
-                       MultU64x32 (VolDescriptorLba, Media->BlockSize),
-                       Media->BlockSize,
+                       VolDescriptorOffset,
+                       SIZE_2KB,
                        VolDescriptor
                        );
     if (EFI_ERROR (Status)) {
@@ -139,17 +149,19 @@ PartitionInstallElToritoChildHandles (
     }
     //
     // Read in the boot El Torito boot catalog
+    // The LBA unit used by El Torito boot catalog is 2KB unit
     //
-    Lba = UNPACK_INT32 (VolDescriptor->BootRecordVolume.EltCatalog);
-    if (Lba > Media->LastBlock) {
+    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 (Lba, Media->BlockSize),
-                       Media->BlockSize,
+                       MultU64x32 (Lba2KB, SIZE_2KB),
+                       SIZE_2KB,
                        Catalog
                        );
     if (EFI_ERROR (Status)) {
@@ -191,7 +203,7 @@ PartitionInstallElToritoChildHandles (
       }
 
       SubBlockSize  = 512;
-      SectorCount   = Catalog->Boot.SectorCount;
+      SectorCount   = Catalog->Boot.SectorCount * (SIZE_2KB / Media->BlockSize);
 
       switch (Catalog->Boot.MediaType) {
 
@@ -236,7 +248,7 @@ PartitionInstallElToritoChildHandles (
 
       CdDev.BootEntry = (UINT32) BootEntry;
       BootEntry++;
-      CdDev.PartitionStart = Catalog->Boot.Lba;
+      CdDev.PartitionStart = Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize);
       if (SectorCount < 2) {
         //
         // When the SectorCount < 2, set the Partition as the whole CD.
@@ -265,8 +277,8 @@ PartitionInstallElToritoChildHandles (
                 BlockIo2,
                 DevicePath,
                 (EFI_DEVICE_PATH_PROTOCOL *) &CdDev,
-                Catalog->Boot.Lba,
-                Catalog->Boot.Lba + CdDev.PartitionSize - 1,
+                Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize),
+                (Catalog->Boot.Lba + CdDev.PartitionSize - 1) * (SIZE_2KB / Media->BlockSize),
                 SubBlockSize,
                 FALSE
                 );
-- 
2.1.1

