summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c')
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c788
1 files changed, 788 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c
new file mode 100644
index 00000000..b321bf71
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c
@@ -0,0 +1,788 @@
+/** @file
+ Scan for an UDF file system on a formatted media.
+
+ Caution: This file requires additional review when modified.
+ This driver will have external input - CD/DVD media.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ FindUdfFileSystem() routine will consume the media properties and do basic
+ validation.
+
+ Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
+ Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
+ Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "Partition.h"
+
+#define MAX_CORRECTION_BLOCKS_NUM 512u
+
+//
+// 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 Device Path GUID for UDF file system
+//
+EFI_GUID gUdfDevPathGuid = EFI_UDF_DEVICE_PATH_GUID;
+
+//
+// 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 }
+ }
+};
+
+/**
+ Find the anchor volume descriptor pointer.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[out] AnchorPoint Anchor volume descriptor pointer.
+ @param[out] LastRecordedBlock Last recorded block.
+
+ @retval EFI_SUCCESS Anchor volume descriptor pointer found.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval other Anchor volume descriptor pointer not found.
+
+**/
+EFI_STATUS
+FindAnchorVolumeDescriptorPointer (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ OUT UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoint,
+ OUT EFI_LBA *LastRecordedBlock
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+ EFI_LBA EndLBA;
+ UDF_DESCRIPTOR_TAG *DescriptorTag;
+ UINTN AvdpsCount;
+ UINTN Size;
+ UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoints;
+ INTN Index;
+ UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPointPtr;
+ EFI_LBA LastAvdpBlockNum;
+
+ //
+ // UDF 2.60, 2.2.3 Anchor Volume Descriptor Pointer
+ //
+ // An Anchor Volume Descriptor Pointer structure shall be recorded in at
+ // least 2 of the following 3 locations on the media: Logical Sector 256,
+ // N - 256 or N, where N is the last *addressable* sector of a volume.
+ //
+ // To figure out what logical sector N is, the SCSI commands READ CAPACITY and
+ // READ TRACK INFORMATION are used, however many drives or medias report their
+ // "last recorded block" wrongly. Although, READ CAPACITY returns the last
+ // readable data block but there might be unwritten blocks, which are located
+ // outside any track and therefore AVDP will not be found at block N.
+ //
+ // That said, we define a magic number of 512 blocks to be used as correction
+ // when attempting to find AVDP and define last block number.
+ //
+ BlockSize = BlockIo->Media->BlockSize;
+ EndLBA = BlockIo->Media->LastBlock;
+ *LastRecordedBlock = EndLBA;
+ AvdpsCount = 0;
+
+ //
+ // Check if the block size of the underlying media can hold the data of an
+ // Anchor Volume Descriptor Pointer
+ //
+ if (BlockSize < sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Media block size 0x%x unable to hold an AVDP.\n",
+ __FUNCTION__,
+ BlockSize
+ ));
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Find AVDP at block 256
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 (256, BlockSize),
+ sizeof (*AnchorPoint),
+ AnchorPoint
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DescriptorTag = &AnchorPoint->DescriptorTag;
+
+ //
+ // Check if read block is a valid AVDP descriptor
+ //
+ if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) {
+ DEBUG ((DEBUG_INFO, "%a: found AVDP at block %d\n", __FUNCTION__, 256));
+ AvdpsCount++;
+ }
+
+ //
+ // Find AVDP at block N - 256
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 ((UINT64)EndLBA - 256, BlockSize),
+ sizeof (*AnchorPoint),
+ AnchorPoint
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check if read block is a valid AVDP descriptor
+ //
+ if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer &&
+ ++AvdpsCount == 2) {
+ DEBUG ((DEBUG_INFO, "%a: found AVDP at block %Ld\n", __FUNCTION__,
+ EndLBA - 256));
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Check if at least one AVDP was found in previous locations
+ //
+ if (AvdpsCount == 0) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ //
+ // Find AVDP at block N
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 ((UINT64)EndLBA, BlockSize),
+ sizeof (*AnchorPoint),
+ AnchorPoint
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check if read block is a valid AVDP descriptor
+ //
+ if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // No AVDP found at block N. Possibly drive/media returned bad last recorded
+ // block, or it is part of unwritten data blocks and outside any track.
+ //
+ // Search backwards for an AVDP from block N-1 through
+ // N-MAX_CORRECTION_BLOCKS_NUM. If any AVDP is found, then correct last block
+ // number for the new UDF partition child handle.
+ //
+ Size = MAX_CORRECTION_BLOCKS_NUM * BlockSize;
+
+ AnchorPoints = AllocateZeroPool (Size);
+ if (AnchorPoints == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Read consecutive MAX_CORRECTION_BLOCKS_NUM disk blocks
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 ((UINT64)EndLBA - MAX_CORRECTION_BLOCKS_NUM, BlockSize),
+ Size,
+ AnchorPoints
+ );
+ if (EFI_ERROR (Status)) {
+ goto Out_Free;
+ }
+
+ Status = EFI_VOLUME_CORRUPTED;
+
+ //
+ // Search for AVDP from blocks N-1 through N-MAX_CORRECTION_BLOCKS_NUM
+ //
+ for (Index = MAX_CORRECTION_BLOCKS_NUM - 2; Index >= 0; Index--) {
+ AnchorPointPtr = (VOID *)((UINTN)AnchorPoints + Index * BlockSize);
+
+ DescriptorTag = &AnchorPointPtr->DescriptorTag;
+
+ //
+ // Check if read block is a valid AVDP descriptor
+ //
+ if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) {
+ //
+ // Calculate last recorded block number
+ //
+ LastAvdpBlockNum = EndLBA - (MAX_CORRECTION_BLOCKS_NUM - Index);
+ DEBUG ((DEBUG_WARN, "%a: found AVDP at block %Ld\n", __FUNCTION__,
+ LastAvdpBlockNum));
+ DEBUG ((DEBUG_WARN, "%a: correcting last block from %Ld to %Ld\n",
+ __FUNCTION__, EndLBA, LastAvdpBlockNum));
+ //
+ // Save read AVDP from last block
+ //
+ CopyMem (AnchorPoint, AnchorPointPtr, sizeof (*AnchorPointPtr));
+ //
+ // Set last recorded block number
+ //
+ *LastRecordedBlock = LastAvdpBlockNum;
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+
+Out_Free:
+ FreePool (AnchorPoints);
+ return Status;
+}
+
+/**
+ Find UDF volume identifiers in a Volume Recognition Sequence.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+
+ @retval EFI_SUCCESS UDF volume identifiers were found.
+ @retval EFI_NOT_FOUND UDF volume identifiers were not found.
+ @retval other Failed to perform disk I/O.
+
+**/
+EFI_STATUS
+FindUdfVolumeIdentifiers (
+ 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;
+
+ 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_NOT_FOUND;
+ }
+ }
+
+ //
+ // Look for "NSR0{2,3}" identifiers in the Extended Area.
+ //
+ Offset += UDF_LOGICAL_SECTOR_SIZE;
+ if (Offset >= EndDiskOffset) {
+ return EFI_NOT_FOUND;
+ }
+
+ 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_NOT_FOUND;
+ }
+
+ //
+ // Look for "TEA01" identifier in the Extended Area
+ //
+ Offset += UDF_LOGICAL_SECTOR_SIZE;
+ if (Offset >= EndDiskOffset) {
+ return EFI_NOT_FOUND;
+ }
+
+ 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_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if Logical Volume Descriptor is supported by current EDK2 UDF file
+ system implementation.
+
+ @param[in] LogicalVolDesc Logical Volume Descriptor pointer.
+
+ @retval TRUE Logical Volume Descriptor is supported.
+ @retval FALSE Logical Volume Descriptor is not supported.
+
+**/
+BOOLEAN
+IsLogicalVolumeDescriptorSupported (
+ UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc
+ )
+{
+ //
+ // Check for a valid UDF revision range
+ //
+ switch (LogicalVolDesc->DomainIdentifier.Suffix.Domain.UdfRevision) {
+ case 0x0102:
+ case 0x0150:
+ case 0x0200:
+ case 0x0201:
+ case 0x0250:
+ case 0x0260:
+ break;
+ default:
+ return FALSE;
+ }
+
+ //
+ // Check for a single Partition Map
+ //
+ if (LogicalVolDesc->NumberOfPartitionMaps > 1) {
+ return FALSE;
+ }
+ //
+ // UDF 1.02 revision supports only Type 1 (Physical) partitions, but
+ // let's check it any way.
+ //
+ // PartitionMap[0] -> type
+ // PartitionMap[1] -> length (in bytes)
+ //
+ if (LogicalVolDesc->PartitionMaps[0] != 1 ||
+ LogicalVolDesc->PartitionMaps[1] != 6) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Find UDF logical volume location and whether it is supported by current EDK2
+ UDF file system implementation.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] AnchorPoint Anchor volume descriptor pointer.
+ @param[in] LastRecordedBlock Last recorded block in media.
+ @param[out] MainVdsStartBlock Main VDS starting block number.
+ @param[out] MainVdsEndBlock Main VDS ending block number.
+
+ @retval EFI_SUCCESS UDF logical volume was found.
+ @retval EFI_VOLUME_CORRUPTED UDF file system structures are corrupted.
+ @retval EFI_UNSUPPORTED UDF logical volume is not supported.
+ @retval other Failed to perform disk I/O.
+
+**/
+EFI_STATUS
+FindLogicalVolumeLocation (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoint,
+ IN EFI_LBA LastRecordedBlock,
+ OUT UINT64 *MainVdsStartBlock,
+ OUT UINT64 *MainVdsEndBlock
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+ UDF_EXTENT_AD *ExtentAd;
+ UINT64 SeqBlocksNum;
+ UINT64 SeqStartBlock;
+ UINT64 GuardMainVdsStartBlock;
+ VOID *Buffer;
+ UINT64 SeqEndBlock;
+ BOOLEAN StopSequence;
+ UINTN LvdsCount;
+ UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc;
+ UDF_DESCRIPTOR_TAG *DescriptorTag;
+
+ BlockSize = BlockIo->Media->BlockSize;
+ ExtentAd = &AnchorPoint->MainVolumeDescriptorSequenceExtent;
+
+ //
+ // UDF 2.60, 2.2.3.1 struct MainVolumeDescriptorSequenceExtent
+ //
+ // The Main Volume Descriptor Sequence Extent shall have a minimum length of
+ // 16 logical sectors.
+ //
+ // Also make sure it does not exceed maximum number of blocks in the disk.
+ //
+ SeqBlocksNum = DivU64x32 ((UINT64)ExtentAd->ExtentLength, BlockSize);
+ if (SeqBlocksNum < 16 || (EFI_LBA)SeqBlocksNum > LastRecordedBlock + 1) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ //
+ // Check for valid Volume Descriptor Sequence starting block number
+ //
+ SeqStartBlock = (UINT64)ExtentAd->ExtentLocation;
+ if (SeqStartBlock > LastRecordedBlock ||
+ SeqStartBlock + SeqBlocksNum - 1 > LastRecordedBlock) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ GuardMainVdsStartBlock = SeqStartBlock;
+
+ //
+ // Allocate buffer for reading disk blocks
+ //
+ Buffer = AllocateZeroPool ((UINTN)BlockSize);
+ if (Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SeqEndBlock = SeqStartBlock + SeqBlocksNum;
+ StopSequence = FALSE;
+ LvdsCount = 0;
+ Status = EFI_VOLUME_CORRUPTED;
+ //
+ // Start Main Volume Descriptor Sequence
+ //
+ for (; SeqStartBlock < SeqEndBlock && !StopSequence; SeqStartBlock++) {
+ //
+ // Read disk block
+ //
+ Status = BlockIo->ReadBlocks (
+ BlockIo,
+ BlockIo->Media->MediaId,
+ SeqStartBlock,
+ BlockSize,
+ Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ goto Out_Free;
+ }
+
+ DescriptorTag = Buffer;
+
+ //
+ // ECMA 167, 8.4.1 Contents of a Volume Descriptor Sequence
+ //
+ // - A Volume Descriptor Sequence shall contain one or more Primary Volume
+ // Descriptors.
+ // - A Volume Descriptor Sequence shall contain zero or more Implementation
+ // Use Volume Descriptors.
+ // - A Volume Descriptor Sequence shall contain zero or more Partition
+ // Descriptors.
+ // - A Volume Descriptor Sequence shall contain zero or more Logical Volume
+ // Descriptors.
+ // - A Volume Descriptor Sequence shall contain zero or more Unallocated
+ // Space Descriptors.
+ //
+ switch (DescriptorTag->TagIdentifier) {
+ case UdfPrimaryVolumeDescriptor:
+ case UdfImplemenationUseVolumeDescriptor:
+ case UdfPartitionDescriptor:
+ case UdfUnallocatedSpaceDescriptor:
+ break;
+
+ case UdfLogicalVolumeDescriptor:
+ LogicalVolDesc = Buffer;
+
+ //
+ // Check for existence of a single LVD and whether it is supported by
+ // current EDK2 UDF file system implementation.
+ //
+ if (++LvdsCount > 1 ||
+ !IsLogicalVolumeDescriptorSupported (LogicalVolDesc)) {
+ Status = EFI_UNSUPPORTED;
+ StopSequence = TRUE;
+ }
+
+ break;
+
+ case UdfTerminatingDescriptor:
+ //
+ // Stop the sequence when we find a Terminating Descriptor
+ // (aka Unallocated Sector), se we don't have to walk all the unallocated
+ // area unnecessarily.
+ //
+ StopSequence = TRUE;
+ break;
+
+ default:
+ //
+ // An invalid Volume Descriptor has been found in the sequece. Volume is
+ // corrupted.
+ //
+ Status = EFI_VOLUME_CORRUPTED;
+ goto Out_Free;
+ }
+ }
+
+ //
+ // Check if LVD was found
+ //
+ if (!EFI_ERROR (Status) && LvdsCount == 1) {
+ *MainVdsStartBlock = GuardMainVdsStartBlock;
+ //
+ // We do not need to read either LVD or PD descriptors to know the last
+ // valid block in the found UDF file system. It's already
+ // LastRecordedBlock.
+ //
+ *MainVdsEndBlock = LastRecordedBlock;
+
+ Status = EFI_SUCCESS;
+ }
+
+Out_Free:
+ //
+ // Free block read buffer
+ //
+ FreePool (Buffer);
+
+ return Status;
+}
+
+/**
+ Find a supported UDF file system in block device.
+
+ @attention This is boundary function that may receive untrusted input.
+ @attention The input is from Partition.
+
+ The CD/DVD media is the external input, so this routine will do basic
+ validation for the media.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[out] StartingLBA UDF file system starting LBA.
+ @param[out] EndingLBA UDF file system starting LBA.
+
+ @retval EFI_SUCCESS UDF file system was found.
+ @retval other UDF file system was not found.
+
+**/
+EFI_STATUS
+FindUdfFileSystem (
+ 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;
+ EFI_LBA LastRecordedBlock;
+
+ //
+ // Find UDF volume identifiers
+ //
+ Status = FindUdfVolumeIdentifiers (BlockIo, DiskIo);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Find Anchor Volume Descriptor Pointer
+ //
+ Status = FindAnchorVolumeDescriptorPointer (
+ BlockIo,
+ DiskIo,
+ &AnchorPoint,
+ &LastRecordedBlock
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Find Logical Volume location
+ //
+ Status = FindLogicalVolumeLocation (
+ BlockIo,
+ DiskIo,
+ &AnchorPoint,
+ LastRecordedBlock,
+ (UINT64 *)StartingLBA,
+ (UINT64 *)EndingLBA
+ );
+
+ return Status;
+}
+
+/**
+ 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
+ )
+{
+ UINT32 RemainderByMediaBlockSize;
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
+ EFI_LBA StartingLBA;
+ EFI_LBA EndingLBA;
+ BOOLEAN ChildCreated;
+
+ Media = BlockIo->Media;
+ ChildCreated = FALSE;
+
+ //
+ // Check if UDF logical block size is multiple of underlying device block size
+ //
+ DivU64x32Remainder (
+ UDF_LOGICAL_SECTOR_SIZE, // Dividend
+ Media->BlockSize, // Divisor
+ &RemainderByMediaBlockSize // Remainder
+ );
+ if (RemainderByMediaBlockSize != 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Detect El Torito feature first.
+ // And always continue to search for UDF.
+ //
+ Status = PartitionInstallElToritoChildHandles (
+ This,
+ Handle,
+ DiskIo,
+ DiskIo2,
+ BlockIo,
+ BlockIo2,
+ DevicePath
+ );
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "PartitionDxe: El Torito standard found on handle 0x%p.\n", Handle));
+ ChildCreated = TRUE;
+ }
+
+ //
+ // Search for an UDF file system on block device
+ //
+ Status = FindUdfFileSystem (BlockIo, DiskIo, &StartingLBA, &EndingLBA);
+ if (EFI_ERROR (Status)) {
+ return (ChildCreated ? EFI_SUCCESS : 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,
+ StartingLBA,
+ EndingLBA,
+ Media->BlockSize,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return (ChildCreated ? EFI_SUCCESS : Status);
+ }
+
+ return EFI_SUCCESS;
+}