From 8aafec2c13360f02152b4c19feb376c7c7cfd60d Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Fri, 8 Sep 2017 09:41:46 -0300 Subject: [PATCH] MdeModulePkg/PartitionDxe: Add UDF file system support 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 Cc: Eric Dong Cc: Laszlo Ersek Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Paulo Alcantara Reviewed-by: Ruiyu Ni --- .../Universal/Disk/PartitionDxe/Partition.c | 9 +- .../Universal/Disk/PartitionDxe/Partition.h | 32 +- .../Disk/PartitionDxe/PartitionDxe.inf | 3 +- .../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.
@@ -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.
@@ -39,7 +39,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include - +#include // // 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 + + 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.39.2