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

Paulo Alcantara posted 6 patches 7 years, 4 months ago
There is a newer version of this series
[edk2] [PATCH v2 2/6] MdeModulePkg/PartitionDxe: Add UDF file system support
Posted by Paulo Alcantara 7 years, 4 months ago
Scan for UDF file system on all block devices, as specified by OSTA
Universal Disk Format Specification 2.60, as well as install a
HARDDRIVE_DEVICE_PATH device path for each one found. The
HARDDRIVE_DEVICE_PATH does not support types other than MBR or GPT, so
it fakes a MBR type and uses signature type of "0xF0" for identifying
UDF file systems.

The fake device path will be later checked by UdfDxe driver in order to
identify valid UDF file systems and provide access to underlying file
system.

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>
---
 .../Universal/Disk/PartitionDxe/Partition.c        |   9 +-
 .../Universal/Disk/PartitionDxe/Partition.h        |  32 ++-
 .../Universal/Disk/PartitionDxe/PartitionDxe.inf   |   3 +-
 MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c     | 307 +++++++++++++++++++++
 4 files changed, 344 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..3fbb3606b8
--- /dev/null
+++ b/MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c
@@ -0,0 +1,307 @@
+/** @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"
+
+#define SIGNATURE_TYPE_UDF 0xF0
+
+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 medium contains an UDF file system.
+
+  @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;
+  HARDDRIVE_DEVICE_PATH        *UdfDevPathPtr;
+  HARDDRIVE_DEVICE_PATH        UdfDevPath;
+  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.
+    //
+    if (DevicePathType (DevicePathNode) == MEDIA_DEVICE_PATH &&
+        DevicePathSubType (DevicePathNode) == MEDIA_CDROM_DP) {
+      return EFI_NOT_FOUND;
+    }
+    //
+    // Avoid duplicate checking and installation of UDF file system child nodes
+    //
+    if (DevicePathType (DevicePathNode) == MEDIA_DEVICE_PATH &&
+        DevicePathSubType (DevicePathNode) == MEDIA_HARDDRIVE_DP) {
+      UdfDevPathPtr = (HARDDRIVE_DEVICE_PATH *)DevicePathNode;
+      if (UdfDevPathPtr->MBRType == MBR_TYPE_PCAT &&
+          UdfDevPathPtr->SignatureType == SIGNATURE_TYPE_UDF) {
+        return EFI_NOT_FOUND;
+      }
+    }
+
+    DevicePathNode = NextDevicePathNode (DevicePathNode);
+  }
+
+  //
+  // Check if block device supports a valid UDF file system
+  //
+  Status = SupportUdfFileSystem (BlockIo, DiskIo);
+  if (EFI_ERROR (Status)) {
+    return EFI_NOT_FOUND;
+  }
+
+  //
+  // Create a fake MBR device path since there is no UDF one
+  //
+  ZeroMem (&UdfDevPath, sizeof (HARDDRIVE_DEVICE_PATH));
+  UdfDevPath.Header.Type     = MEDIA_DEVICE_PATH;
+  UdfDevPath.Header.SubType  = MEDIA_HARDDRIVE_DP;
+  SetDevicePathNodeLength (&UdfDevPath.Header, sizeof (UdfDevPath));
+  UdfDevPath.MBRType         = MBR_TYPE_PCAT;
+  UdfDevPath.SignatureType   = SIGNATURE_TYPE_UDF;
+  UdfDevPath.PartitionNumber = 1;
+  UdfDevPath.PartitionStart  = 0;
+  UdfDevPath.PartitionSize   = Media->LastBlock + 1;
+
+  //
+  // 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 *)&UdfDevPath,
+    &PartitionInfo,
+    UdfDevPath.PartitionStart,
+    UdfDevPath.PartitionStart + UdfDevPath.PartitionSize - 1,
+    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