[edk2] [PATCH 2/3] MdeModulePkg/PartitionDxe: Fix creation of UDF logical partition

Paulo Alcantara posted 3 patches 7 years, 3 months ago
There is a newer version of this series
[edk2] [PATCH 2/3] MdeModulePkg/PartitionDxe: Fix creation of UDF logical partition
Posted by Paulo Alcantara 7 years, 3 months ago
Do not use entire block device size for the UDF logical partition,
instead reserve the appropriate space (LVD space) for it.

Cc: Eric Dong <eric.dong@intel.com>
Cc: Ruiyu Ni <ruiyu.ni@intel.com>
Cc: Star Zeng <star.zeng@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Reported-by: Ruiyu Ni <ruiyu.ni@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
---
 MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c | 307 +++++++++++++++++++++++--
 1 file changed, 283 insertions(+), 24 deletions(-)

diff --git a/MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c b/MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c
index 7856b5dfc1..b00369ba6d 100644
--- a/MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c
+++ b/MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c
@@ -84,24 +84,8 @@ FindAnchorVolumeDescriptorPointer (
   return EFI_VOLUME_CORRUPTED;
 }
 
-/**
-  Check if block device supports a valid UDF file system as specified by OSTA
-  Universal Disk Format Specification 2.60.
-
-  @param[in]   BlockIo  BlockIo interface.
-  @param[in]   DiskIo   DiskIo interface.
-
-  @retval EFI_SUCCESS          UDF file system found.
-  @retval EFI_UNSUPPORTED      UDF file system not found.
-  @retval EFI_NO_MEDIA         The device has no media.
-  @retval EFI_DEVICE_ERROR     The device reported an error.
-  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
-  @retval EFI_OUT_OF_RESOURCES The scan was not successful due to lack of
-                               resources.
-
-**/
 EFI_STATUS
-SupportUdfFileSystem (
+FindUdfVolumeIdentifiers (
   IN EFI_BLOCK_IO_PROTOCOL  *BlockIo,
   IN EFI_DISK_IO_PROTOCOL   *DiskIo
   )
@@ -111,7 +95,6 @@ SupportUdfFileSystem (
   UINT64                                EndDiskOffset;
   CDROM_VOLUME_DESCRIPTOR               VolDescriptor;
   CDROM_VOLUME_DESCRIPTOR               TerminatingVolDescriptor;
-  UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER  AnchorPoint;
 
   ZeroMem ((VOID *)&TerminatingVolDescriptor, sizeof (CDROM_VOLUME_DESCRIPTOR));
 
@@ -207,12 +190,286 @@ SupportUdfFileSystem (
     return EFI_UNSUPPORTED;
   }
 
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+GetPartitionNumber (
+  IN   UDF_LOGICAL_VOLUME_DESCRIPTOR  *LogicalVolDesc,
+  OUT  UINT16                         *PartitionNum
+  )
+{
+  EFI_STATUS                      Status;
+  UDF_LONG_ALLOCATION_DESCRIPTOR  *LongAd;
+
+  Status = EFI_SUCCESS;
+
+  switch (LV_UDF_REVISION (LogicalVolDesc)) {
+  case 0x0102:
+    //
+    // UDF 1.20 only supports Type 1 Partition
+    //
+    *PartitionNum = *(UINT16 *)((UINTN)&LogicalVolDesc->PartitionMaps[4]);
+    break;
+  case 0x0150:
+    //
+    // Ensure Type 1 Partition map
+    //
+    ASSERT (LogicalVolDesc->PartitionMaps[0] == 1 &&
+            LogicalVolDesc->PartitionMaps[1] == 6);
+    *PartitionNum = *(UINT16 *)((UINTN)&LogicalVolDesc->PartitionMaps[4]);
+    break;
+  case 0x0260:
+    LongAd = &LogicalVolDesc->LogicalVolumeContentsUse;
+    *PartitionNum = LongAd->ExtentLocation.PartitionReferenceNumber;
+    break;
+  default:
+    //
+    // Unhandled UDF revision
+    //
+    Status = EFI_VOLUME_CORRUPTED;
+    break;
+  }
+
+  return Status;
+}
+
+EFI_STATUS
+FindLogicalVolumeLocation (
+  IN   EFI_BLOCK_IO_PROTOCOL                 *BlockIo,
+  IN   EFI_DISK_IO_PROTOCOL                  *DiskIo,
+  IN   UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER  *AnchorPoint,
+  OUT  UINT64                                *MainVdsStartLsn,
+  OUT  UINT64                                *LogicalVolEndLsn
+  )
+{
+  EFI_STATUS                     Status;
+  UINT32                         BlockSize;
+  EFI_LBA                        LastBlock;
+  UDF_EXTENT_AD                  *ExtentAd;
+  UINT64                         StartingLsn;
+  UINT64                         EndingLsn;
+  VOID                           *Buffer;
+  UDF_LOGICAL_VOLUME_DESCRIPTOR  *LogicalVolDesc;
+  UDF_PARTITION_DESCRIPTOR       *PartitionDesc;
+  UINT64                         GuardMainVdsStartLsn;
+  UINT16                         PartitionNum;
+
+  BlockSize             = BlockIo->Media->BlockSize;
+  LastBlock             = BlockIo->Media->LastBlock;
+  ExtentAd              = &AnchorPoint->MainVolumeDescriptorSequenceExtent;
+  StartingLsn           = (UINT64)ExtentAd->ExtentLocation;
+  EndingLsn             =
+    StartingLsn + DivU64x32 ((UINT64)ExtentAd->ExtentLength, BlockSize);
+
+  LogicalVolDesc        = NULL;
+  PartitionDesc         = NULL;
+  GuardMainVdsStartLsn  = StartingLsn;
+
+  //
+  // Allocate buffer for reading disk blocks
+  //
+  Buffer = AllocateZeroPool (BlockSize);
+  if (Buffer == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Status = EFI_VOLUME_CORRUPTED;
+
+  //
+  // As per UDF 2.60 specification:
+  //
+  // There shall be exactly one prevailing Logical Volume Descriptor
+  // recorded per Volume Set.
+  //
+  // Start Main Volume Descriptor Sequence and find Logical Volume Descriptor
+  //
+  while (StartingLsn <= EndingLsn) {
+    //
+    // Read disk block
+    //
+    Status = DiskIo->ReadDisk (
+      DiskIo,
+      BlockIo->Media->MediaId,
+      MultU64x32 (StartingLsn, BlockSize),
+      BlockSize,
+      Buffer
+      );
+    if (EFI_ERROR (Status)) {
+      goto Out_Free;
+    }
+
+    //
+    // Check if read block is a Terminating Descriptor
+    //
+    if (IS_TD (Buffer)) {
+      //
+      // Stop Main Volume Descriptor Sequence
+      //
+      break;
+    }
+
+    //
+    // Check if read block is a Logical Volume Descriptor
+    //
+    if (IS_LVD (Buffer)) {
+      //
+      // Ensure only one LVD (Logical Volume Descriptor) is read
+      //
+      ASSERT (LogicalVolDesc == NULL);
+
+      //
+      // As per UDF 2.60 specification:
+      //
+      // For the purpose of interchange, Partition Maps shall be limited to
+      // Partition Map type 1, except type 2 maps.
+      //
+      // NOTE: Type 1 Partitions are the only supported in this implementation.
+      //
+      LogicalVolDesc = AllocateZeroPool (sizeof (*LogicalVolDesc));
+      if (LogicalVolDesc == NULL) {
+        Status = EFI_OUT_OF_RESOURCES;
+        goto Out_Free;
+      }
+
+      //
+      // Save Logical Volume Descriptor
+      //
+      CopyMem (LogicalVolDesc, Buffer, sizeof (*LogicalVolDesc));
+    } else if (IS_PD (Buffer)) {
+      //
+      // Ensure only one PD (Partition Descriptor) is read
+      //
+      ASSERT (PartitionDesc == NULL);
+      //
+      // Found a Partition Descriptor.
+      //
+      // As per UDF 2.60 specification:
+      //
+      // A Partition Descriptor Access Type of read-only, rewritable,
+      // overwritable, write-once and pseudo-overwritable shall be
+      // supported. There shall be exactly one prevailing Partition
+      // Descriptor recorded per volume, with one exception. For Volume
+      // Sets that consist of single volume, the volume may contain 2 non-
+      // overlapping Partitions with 2 prevailing Partition Descriptors only
+      // if one has an Access Type of read-only and the other has an
+      // Access Type of rewritable, overwritable, or write-once. The
+      // Logical Volume for this volume would consist of the contents of
+      // both partitions.
+      //
+      PartitionDesc = AllocateZeroPool (sizeof (*PartitionDesc));
+      if (PartitionDesc == NULL) {
+        Status = EFI_OUT_OF_RESOURCES;
+        goto Out_Free;
+      }
+
+      //
+      // Save Partition Descriptor
+      //
+      CopyMem (PartitionDesc, Buffer, sizeof (*PartitionDesc));
+    }
+
+    //
+    // Go to next disk block
+    //
+    StartingLsn++;
+  }
+
+  //
+  // Check if LVD and PD were found
+  //
+  if (LogicalVolDesc != NULL && PartitionDesc != NULL) {
+    //
+    // Get partition number from Partition map in LVD descriptor
+    //
+    Status = GetPartitionNumber (LogicalVolDesc, &PartitionNum);
+    if (EFI_ERROR (Status)) {
+      goto Out_Free;
+    }
+
+    //
+    // Make sure we're handling expected Partition Descriptor
+    //
+    ASSERT (PartitionNum == PartitionDesc->PartitionNumber);
+
+    //
+    // Cover the main VDS area so UdfDxe driver will also be able to get LVD and
+    // PD descriptors out from the file system.
+    //
+    *MainVdsStartLsn = GuardMainVdsStartLsn;
+    *LogicalVolEndLsn = *MainVdsStartLsn + (UINT64)ExtentAd->ExtentLength;
+
+    //
+    // Cover UDF partition area
+    //
+    *LogicalVolEndLsn +=
+      ((UINT64)PartitionDesc->PartitionStartingLocation -
+       *LogicalVolEndLsn) + PartitionDesc->PartitionLength - 1;
+    //
+    // Ensure to not attempt reading past end of device
+    //
+    ASSERT (*LogicalVolEndLsn <= LastBlock);
+
+    Status = EFI_SUCCESS;
+  }
+
+Out_Free:
+  //
+  // Free block read buffer
+  //
+  FreePool (Buffer);
+  //
+  // Free Logical Volume Descriptor
+  //
+  if (LogicalVolDesc != NULL) {
+    FreePool (LogicalVolDesc);
+  }
+  //
+  // Free Partition Descriptor
+  //
+  if (PartitionDesc != NULL) {
+    FreePool (PartitionDesc);
+  }
+
+  return Status;
+}
+
+EFI_STATUS
+FindUdfLogicalVolume (
+  IN EFI_BLOCK_IO_PROTOCOL  *BlockIo,
+  IN EFI_DISK_IO_PROTOCOL   *DiskIo,
+  OUT EFI_LBA               *StartingLBA,
+  OUT EFI_LBA               *EndingLBA
+  )
+{
+  EFI_STATUS Status;
+  UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER  AnchorPoint;
+
+  //
+  // Find UDF volume identifiers
+  //
+  Status = FindUdfVolumeIdentifiers (BlockIo, DiskIo);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Find Anchor Volume Descriptor Pointer
+  //
   Status = FindAnchorVolumeDescriptorPointer (BlockIo, DiskIo, &AnchorPoint);
   if (EFI_ERROR (Status)) {
-    return EFI_UNSUPPORTED;
+    return Status;
   }
 
-  return EFI_SUCCESS;
+  //
+  // Find Logical Volume location
+  //
+  Status = FindLogicalVolumeLocation (
+    BlockIo, DiskIo, &AnchorPoint, (UINT64 *)StartingLBA,
+    (UINT64 *)EndingLBA
+    );
+
+  return Status;
 }
 
 /**
@@ -250,6 +507,8 @@ PartitionInstallUdfChildHandles (
   EFI_GUID                     *VendorDefinedGuid;
   EFI_GUID                     UdfDevPathGuid = EFI_UDF_DEVICE_PATH_GUID;
   EFI_PARTITION_INFO_PROTOCOL  PartitionInfo;
+  EFI_LBA                      StartingLBA;
+  EFI_LBA                      EndingLBA;
 
   Media = BlockIo->Media;
 
@@ -291,9 +550,9 @@ PartitionInstallUdfChildHandles (
   }
 
   //
-  // Check if block device supports an UDF file system
+  // Find UDF logical volume on block device
   //
-  Status = SupportUdfFileSystem (BlockIo, DiskIo);
+  Status = FindUdfLogicalVolume (BlockIo, DiskIo, &StartingLBA, &EndingLBA);
   if (EFI_ERROR (Status)) {
     return EFI_NOT_FOUND;
   }
@@ -318,8 +577,8 @@ PartitionInstallUdfChildHandles (
     DevicePath,
     (EFI_DEVICE_PATH_PROTOCOL *)&gUdfDevicePath,
     &PartitionInfo,
-    0,
-    Media->LastBlock,
+    StartingLBA,
+    EndingLBA,
     Media->BlockSize
     );
   if (!EFI_ERROR (Status)) {
-- 
2.11.0

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel