[edk2] [PATCH v5 2/6] MdeModulePkg/PartitionDxe: Add UDF file system support

Paulo Alcantara posted 6 patches 7 years, 3 months ago
There is a newer version of this series
[edk2] [PATCH v5 2/6] MdeModulePkg/PartitionDxe: Add UDF file system support
Posted by Paulo Alcantara 7 years, 3 months ago
Scan for UDF file systems on all block devices, as specified by OSTA
Universal Disk Format Specification 2.60, and install a Vendor-Defined
Media Device Path for each file system found.

The Vendor-Defined Media Device Path for the UDF file system is then
checked by UdfDxe to decide whether or not start the driver.

Cc: Star Zeng <star.zeng@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
Reviewed-by: Ruiyu Ni <ruiyu.ni@intel.com>
---
 .../Universal/Disk/PartitionDxe/Partition.c        |   9 +-
 .../Universal/Disk/PartitionDxe/Partition.h        |  32 ++-
 .../Universal/Disk/PartitionDxe/PartitionDxe.inf   |   3 +-
 MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c     | 318 +++++++++++++++++++++
 4 files changed, 355 insertions(+), 7 deletions(-)
 create mode 100644 MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c

diff --git a/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c b/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c
index 5a7d119b43..f6030e0897 100644
--- a/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c
+++ b/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c
@@ -1,7 +1,7 @@
 /** @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
+  of the raw block devices media. Currently "El Torito CD-ROM", UDF, Legacy
   MBR, and GPT partition schemes are supported.
 
 Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
@@ -45,6 +45,7 @@ PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable[] = {
   PartitionInstallGptChildHandles,
   PartitionInstallElToritoChildHandles,
   PartitionInstallMbrChildHandles,
+  PartitionInstallUdfChildHandles,
   NULL
 };
 
@@ -305,9 +306,9 @@ PartitionDriverBindingStart (
   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.
+    // Try for GPT, then El Torito, then UDF, 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) {
diff --git a/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.h b/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.h
index f2f6185317..c763c676a9 100644
--- a/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.h
+++ b/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.h
@@ -1,7 +1,7 @@
 /** @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 
+  of the raw block devices media. Currently "El Torito CD-ROM", UDF, Legacy
   MBR, and GPT partition schemes are supported.
 
 Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
@@ -39,7 +39,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 
 #include <IndustryStandard/Mbr.h>
 #include <IndustryStandard/ElTorito.h>
-
+#include <IndustryStandard/Udf.h>
 
 //
 // Partition private data
@@ -445,6 +445,34 @@ PartitionInstallMbrChildHandles (
   IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath
   );
 
+/**
+  Install child handles if the Handle supports UDF/ECMA-167 volume 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
+PartitionInstallUdfChildHandles (
+  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
+  );
+
 typedef
 EFI_STATUS
 (*PARTITION_DETECT_ROUTINE) (
diff --git a/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf b/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf
index 48212773e8..fb2ea87a9d 100644
--- a/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf
+++ b/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf
@@ -4,7 +4,7 @@
 #  This module produces the logical Block I/O device that represents
 #  the bytes from Start to End of the Parent Block I/O device.
 #  The partition of physical BlockIo device supported is one of legacy MBR, GPT,
-#  and "El Torito" partitions.
+#  UDF and "El Torito" partitions.
 #
 #  Caution: This module requires additional review when modified.
 #  This driver will have external input - disk partition.
@@ -46,6 +46,7 @@
   Mbr.c
   Gpt.c
   ElTorito.c
+  Udf.c
   Partition.c
   Partition.h
 
diff --git a/MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c b/MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c
new file mode 100644
index 0000000000..c1d44809bf
--- /dev/null
+++ b/MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c
@@ -0,0 +1,318 @@
+/** @file
+  Scan for an UDF file system on a formatted media.
+
+  Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
+
+  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"
+
+//
+// C5BD4D42-1A76-4996-8956-73CDA326CD0A
+//
+#define EFI_UDF_DEVICE_PATH_GUID                        \
+  { 0xC5BD4D42, 0x1A76, 0x4996,                         \
+    { 0x89, 0x56, 0x73, 0xCD, 0xA3, 0x26, 0xCD, 0x0A }  \
+  }
+
+typedef struct {
+  VENDOR_DEVICE_PATH        DevicePath;
+  EFI_DEVICE_PATH_PROTOCOL  End;
+} UDF_DEVICE_PATH;
+
+//
+// Vendor-Defined Media Device Path for UDF file system
+//
+UDF_DEVICE_PATH gUdfDevicePath = {
+  { { MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP,
+      { sizeof (VENDOR_DEVICE_PATH), 0 } },
+    EFI_UDF_DEVICE_PATH_GUID
+  },
+  { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
+    { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
+  }
+};
+
+EFI_STATUS
+FindAnchorVolumeDescriptorPointer (
+  IN   EFI_BLOCK_IO_PROTOCOL                 *BlockIo,
+  IN   EFI_DISK_IO_PROTOCOL                  *DiskIo,
+  OUT  UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER  *AnchorPoint
+  )
+{
+  EFI_STATUS  Status;
+  UINT32      BlockSize = BlockIo->Media->BlockSize;
+  EFI_LBA     EndLBA = BlockIo->Media->LastBlock;
+  EFI_LBA     DescriptorLBAs[] = { 256, EndLBA - 256, EndLBA, 512 };
+  UINTN       Index;
+
+  for (Index = 0; Index < ARRAY_SIZE (DescriptorLBAs); Index++) {
+    Status = DiskIo->ReadDisk (
+      DiskIo,
+      BlockIo->Media->MediaId,
+      MultU64x32 (DescriptorLBAs[Index], BlockSize),
+      sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER),
+      (VOID *)AnchorPoint
+      );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+    //
+    // Check if read LBA has a valid AVDP descriptor.
+    //
+    if (IS_AVDP (AnchorPoint)) {
+      return EFI_SUCCESS;
+    }
+  }
+  //
+  // No AVDP found.
+  //
+  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 (
+  IN EFI_BLOCK_IO_PROTOCOL  *BlockIo,
+  IN EFI_DISK_IO_PROTOCOL   *DiskIo
+  )
+{
+  EFI_STATUS                            Status;
+  UINT64                                Offset;
+  UINT64                                EndDiskOffset;
+  CDROM_VOLUME_DESCRIPTOR               VolDescriptor;
+  CDROM_VOLUME_DESCRIPTOR               TerminatingVolDescriptor;
+  UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER  AnchorPoint;
+
+  ZeroMem ((VOID *)&TerminatingVolDescriptor, sizeof (CDROM_VOLUME_DESCRIPTOR));
+
+  //
+  // Start Volume Recognition Sequence
+  //
+  EndDiskOffset = MultU64x32 (BlockIo->Media->LastBlock,
+                              BlockIo->Media->BlockSize);
+
+  for (Offset = UDF_VRS_START_OFFSET; Offset < EndDiskOffset;
+       Offset += UDF_LOGICAL_SECTOR_SIZE) {
+    //
+    // Check if block device has a Volume Structure Descriptor and an Extended
+    // Area.
+    //
+    Status = DiskIo->ReadDisk (
+      DiskIo,
+      BlockIo->Media->MediaId,
+      Offset,
+      sizeof (CDROM_VOLUME_DESCRIPTOR),
+      (VOID *)&VolDescriptor
+      );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    if (CompareMem ((VOID *)VolDescriptor.Unknown.Id,
+                    (VOID *)UDF_BEA_IDENTIFIER,
+                    sizeof (VolDescriptor.Unknown.Id)) == 0) {
+      break;
+    }
+
+    if ((CompareMem ((VOID *)VolDescriptor.Unknown.Id,
+                     (VOID *)CDVOL_ID,
+                     sizeof (VolDescriptor.Unknown.Id)) != 0) ||
+        (CompareMem ((VOID *)&VolDescriptor,
+                     (VOID *)&TerminatingVolDescriptor,
+                     sizeof (CDROM_VOLUME_DESCRIPTOR)) == 0)) {
+      return EFI_UNSUPPORTED;
+    }
+  }
+
+  //
+  // Look for "NSR0{2,3}" identifiers in the Extended Area.
+  //
+  Offset += UDF_LOGICAL_SECTOR_SIZE;
+  if (Offset >= EndDiskOffset) {
+    return EFI_UNSUPPORTED;
+  }
+
+  Status = DiskIo->ReadDisk (
+    DiskIo,
+    BlockIo->Media->MediaId,
+    Offset,
+    sizeof (CDROM_VOLUME_DESCRIPTOR),
+    (VOID *)&VolDescriptor
+    );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if ((CompareMem ((VOID *)VolDescriptor.Unknown.Id,
+                   (VOID *)UDF_NSR2_IDENTIFIER,
+                   sizeof (VolDescriptor.Unknown.Id)) != 0) &&
+      (CompareMem ((VOID *)VolDescriptor.Unknown.Id,
+                   (VOID *)UDF_NSR3_IDENTIFIER,
+                   sizeof (VolDescriptor.Unknown.Id)) != 0)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Look for "TEA01" identifier in the Extended Area
+  //
+  Offset += UDF_LOGICAL_SECTOR_SIZE;
+  if (Offset >= EndDiskOffset) {
+    return EFI_UNSUPPORTED;
+  }
+
+  Status = DiskIo->ReadDisk (
+    DiskIo,
+    BlockIo->Media->MediaId,
+    Offset,
+    sizeof (CDROM_VOLUME_DESCRIPTOR),
+    (VOID *)&VolDescriptor
+    );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (CompareMem ((VOID *)VolDescriptor.Unknown.Id,
+                  (VOID *)UDF_TEA_IDENTIFIER,
+                  sizeof (VolDescriptor.Unknown.Id)) != 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  Status = FindAnchorVolumeDescriptorPointer (BlockIo, DiskIo, &AnchorPoint);
+  if (EFI_ERROR (Status)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Install child handles if the Handle supports UDF/ECMA-167 volume 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
+PartitionInstallUdfChildHandles (
+  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;
+  EFI_BLOCK_IO_MEDIA           *Media;
+  EFI_DEVICE_PATH_PROTOCOL     *DevicePathNode;
+  EFI_GUID                     *VendorDefinedGuid;
+  EFI_GUID                     UdfDevPathGuid = EFI_UDF_DEVICE_PATH_GUID;
+  EFI_PARTITION_INFO_PROTOCOL  PartitionInfo;
+
+  Media = BlockIo->Media;
+
+  //
+  // Check if UDF logical block size is multiple of underlying device block size
+  //
+  if ((UDF_LOGICAL_SECTOR_SIZE % Media->BlockSize) != 0 ||
+      Media->BlockSize > UDF_LOGICAL_SECTOR_SIZE) {
+    return EFI_NOT_FOUND;
+  }
+
+  DevicePathNode = DevicePath;
+  while (!IsDevicePathEnd (DevicePathNode)) {
+    //
+    // Do not allow checking for UDF file systems in CDROM "El Torito"
+    // partitions, and skip duplicate installation of UDF file system child
+    // nodes.
+    //
+    if (DevicePathType (DevicePathNode) == MEDIA_DEVICE_PATH) {
+      if (DevicePathSubType (DevicePathNode) == MEDIA_CDROM_DP) {
+        return EFI_NOT_FOUND;
+      }
+      if (DevicePathSubType (DevicePathNode) == MEDIA_VENDOR_DP) {
+        VendorDefinedGuid = (EFI_GUID *)((UINTN)DevicePathNode +
+                                         OFFSET_OF (VENDOR_DEVICE_PATH, Guid));
+        if (CompareGuid (VendorDefinedGuid, &UdfDevPathGuid)) {
+          return EFI_NOT_FOUND;
+        }
+      }
+    }
+    //
+    // Try next device path node
+    //
+    DevicePathNode = NextDevicePathNode (DevicePathNode);
+  }
+
+  //
+  // Check if block device supports an UDF file system
+  //
+  Status = SupportUdfFileSystem (BlockIo, DiskIo);
+  if (EFI_ERROR (Status)) {
+    return EFI_NOT_FOUND;
+  }
+
+  //
+  // Create Partition Info protocol for UDF file system
+  //
+  ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
+  PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
+  PartitionInfo.Type = PARTITION_TYPE_OTHER;
+
+  //
+  // Install partition child handle for UDF file system
+  //
+  Status = PartitionInstallChildHandle (
+    This,
+    Handle,
+    DiskIo,
+    DiskIo2,
+    BlockIo,
+    BlockIo2,
+    DevicePath,
+    (EFI_DEVICE_PATH_PROTOCOL *)&gUdfDevicePath,
+    &PartitionInfo,
+    0,
+    Media->LastBlock,
+    Media->BlockSize
+    );
+  if (!EFI_ERROR (Status)) {
+    Status = EFI_NOT_FOUND;
+  }
+
+  return Status;
+}
-- 
2.11.0

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