/** @file\r
Scan for an UDF file system on a formatted media.\r
\r
- Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>\r
+ Caution: This file requires additional review when modified.\r
+ This driver will have external input - CD/DVD media.\r
+ This external input must be validated carefully to avoid security issue like\r
+ buffer overflow, integer overflow.\r
+\r
+ FindUdfFileSystem() routine will consume the media properties and do basic\r
+ validation.\r
\r
- This program and the accompanying materials are licensed and made available\r
- under the terms and conditions of the BSD License which accompanies this\r
- distribution. The full text of the license may be found at\r
- http://opensource.org/licenses/bsd-license.php\r
+ Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.\r
+ Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>\r
+ Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>\r
\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
- WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
**/\r
\r
#include "Partition.h"\r
\r
+#define MAX_CORRECTION_BLOCKS_NUM 512u\r
+\r
//\r
// C5BD4D42-1A76-4996-8956-73CDA326CD0A\r
//\r
EFI_DEVICE_PATH_PROTOCOL End;\r
} UDF_DEVICE_PATH;\r
\r
+//\r
+// Vendor-Defined Device Path GUID for UDF file system\r
+//\r
+EFI_GUID gUdfDevPathGuid = EFI_UDF_DEVICE_PATH_GUID;\r
+\r
//\r
// Vendor-Defined Media Device Path for UDF file system\r
//\r
/**\r
Find the anchor volume descriptor pointer.\r
\r
- @param[in] BlockIo BlockIo interface.\r
- @param[in] DiskIo DiskIo interface.\r
- @param[out] AnchorPoint Anchor volume descriptor pointer.\r
+ @param[in] BlockIo BlockIo interface.\r
+ @param[in] DiskIo DiskIo interface.\r
+ @param[out] AnchorPoint Anchor volume descriptor pointer.\r
+ @param[out] LastRecordedBlock Last recorded block.\r
\r
- @retval EFI_SUCCESS Anchor volume descriptor pointer found.\r
- @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
- @retval other Anchor volume descriptor pointer not found.\r
+ @retval EFI_SUCCESS Anchor volume descriptor pointer found.\r
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+ @retval other Anchor volume descriptor pointer not found.\r
\r
**/\r
EFI_STATUS\r
FindAnchorVolumeDescriptorPointer (\r
IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
- OUT UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoint\r
+ OUT UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoint,\r
+ OUT EFI_LBA *LastRecordedBlock\r
)\r
{\r
- EFI_STATUS Status;\r
- UINT32 BlockSize;\r
- EFI_LBA EndLBA;\r
- EFI_LBA DescriptorLBAs[4];\r
- UINTN Index;\r
+ EFI_STATUS Status;\r
+ UINT32 BlockSize;\r
+ EFI_LBA EndLBA;\r
+ UDF_DESCRIPTOR_TAG *DescriptorTag;\r
+ UINTN AvdpsCount;\r
+ UINTN Size;\r
+ UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoints;\r
+ INTN Index;\r
+ UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPointPtr;\r
+ EFI_LBA LastAvdpBlockNum;\r
\r
+ //\r
+ // UDF 2.60, 2.2.3 Anchor Volume Descriptor Pointer\r
+ //\r
+ // An Anchor Volume Descriptor Pointer structure shall be recorded in at\r
+ // least 2 of the following 3 locations on the media: Logical Sector 256,\r
+ // N - 256 or N, where N is the last *addressable* sector of a volume.\r
+ //\r
+ // To figure out what logical sector N is, the SCSI commands READ CAPACITY and\r
+ // READ TRACK INFORMATION are used, however many drives or medias report their\r
+ // "last recorded block" wrongly. Although, READ CAPACITY returns the last\r
+ // readable data block but there might be unwritten blocks, which are located\r
+ // outside any track and therefore AVDP will not be found at block N.\r
+ //\r
+ // That said, we define a magic number of 512 blocks to be used as correction\r
+ // when attempting to find AVDP and define last block number.\r
+ //\r
BlockSize = BlockIo->Media->BlockSize;\r
EndLBA = BlockIo->Media->LastBlock;\r
- DescriptorLBAs[0] = 256;\r
- DescriptorLBAs[1] = EndLBA - 256;\r
- DescriptorLBAs[2] = EndLBA;\r
- DescriptorLBAs[3] = 512;\r
+ *LastRecordedBlock = EndLBA;\r
+ AvdpsCount = 0;\r
+\r
+ //\r
+ // Check if the block size of the underlying media can hold the data of an\r
+ // Anchor Volume Descriptor Pointer\r
+ //\r
+ if (BlockSize < sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "%a: Media block size 0x%x unable to hold an AVDP.\n",\r
+ __FUNCTION__,\r
+ BlockSize\r
+ ));\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Find AVDP at block 256\r
+ //\r
+ Status = DiskIo->ReadDisk (\r
+ DiskIo,\r
+ BlockIo->Media->MediaId,\r
+ MultU64x32 (256, BlockSize),\r
+ sizeof (*AnchorPoint),\r
+ AnchorPoint\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ DescriptorTag = &AnchorPoint->DescriptorTag;\r
+\r
+ //\r
+ // Check if read block is a valid AVDP descriptor\r
+ //\r
+ if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) {\r
+ DEBUG ((DEBUG_INFO, "%a: found AVDP at block %d\n", __FUNCTION__, 256));\r
+ AvdpsCount++;\r
+ }\r
+\r
+ //\r
+ // Find AVDP at block N - 256\r
+ //\r
+ Status = DiskIo->ReadDisk (\r
+ DiskIo,\r
+ BlockIo->Media->MediaId,\r
+ MultU64x32 ((UINT64)EndLBA - 256, BlockSize),\r
+ sizeof (*AnchorPoint),\r
+ AnchorPoint\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Check if read block is a valid AVDP descriptor\r
+ //\r
+ if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer &&\r
+ ++AvdpsCount == 2) {\r
+ DEBUG ((DEBUG_INFO, "%a: found AVDP at block %Ld\n", __FUNCTION__,\r
+ EndLBA - 256));\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Check if at least one AVDP was found in previous locations\r
+ //\r
+ if (AvdpsCount == 0) {\r
+ return EFI_VOLUME_CORRUPTED;\r
+ }\r
+\r
+ //\r
+ // Find AVDP at block N\r
+ //\r
+ Status = DiskIo->ReadDisk (\r
+ DiskIo,\r
+ BlockIo->Media->MediaId,\r
+ MultU64x32 ((UINT64)EndLBA, BlockSize),\r
+ sizeof (*AnchorPoint),\r
+ AnchorPoint\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Check if read block is a valid AVDP descriptor\r
+ //\r
+ if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // No AVDP found at block N. Possibly drive/media returned bad last recorded\r
+ // block, or it is part of unwritten data blocks and outside any track.\r
+ //\r
+ // Search backwards for an AVDP from block N-1 through\r
+ // N-MAX_CORRECTION_BLOCKS_NUM. If any AVDP is found, then correct last block\r
+ // number for the new UDF partition child handle.\r
+ //\r
+ Size = MAX_CORRECTION_BLOCKS_NUM * BlockSize;\r
+\r
+ AnchorPoints = AllocateZeroPool (Size);\r
+ if (AnchorPoints == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Read consecutive MAX_CORRECTION_BLOCKS_NUM disk blocks\r
+ //\r
+ Status = DiskIo->ReadDisk (\r
+ DiskIo,\r
+ BlockIo->Media->MediaId,\r
+ MultU64x32 ((UINT64)EndLBA - MAX_CORRECTION_BLOCKS_NUM, BlockSize),\r
+ Size,\r
+ AnchorPoints\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Out_Free;\r
+ }\r
+\r
+ Status = EFI_VOLUME_CORRUPTED;\r
+\r
+ //\r
+ // Search for AVDP from blocks N-1 through N-MAX_CORRECTION_BLOCKS_NUM\r
+ //\r
+ for (Index = MAX_CORRECTION_BLOCKS_NUM - 2; Index >= 0; Index--) {\r
+ AnchorPointPtr = (VOID *)((UINTN)AnchorPoints + Index * BlockSize);\r
+\r
+ DescriptorTag = &AnchorPointPtr->DescriptorTag;\r
\r
- for (Index = 0; Index < ARRAY_SIZE (DescriptorLBAs); Index++) {\r
- Status = DiskIo->ReadDisk (\r
- DiskIo,\r
- BlockIo->Media->MediaId,\r
- MultU64x32 (DescriptorLBAs[Index], BlockSize),\r
- sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER),\r
- (VOID *)AnchorPoint\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
//\r
- // Check if read LBA has a valid AVDP descriptor.\r
+ // Check if read block is a valid AVDP descriptor\r
//\r
- if (IS_AVDP (AnchorPoint)) {\r
- return EFI_SUCCESS;\r
+ if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) {\r
+ //\r
+ // Calculate last recorded block number\r
+ //\r
+ LastAvdpBlockNum = EndLBA - (MAX_CORRECTION_BLOCKS_NUM - Index);\r
+ DEBUG ((DEBUG_WARN, "%a: found AVDP at block %Ld\n", __FUNCTION__,\r
+ LastAvdpBlockNum));\r
+ DEBUG ((DEBUG_WARN, "%a: correcting last block from %Ld to %Ld\n",\r
+ __FUNCTION__, EndLBA, LastAvdpBlockNum));\r
+ //\r
+ // Save read AVDP from last block\r
+ //\r
+ CopyMem (AnchorPoint, AnchorPointPtr, sizeof (*AnchorPointPtr));\r
+ //\r
+ // Set last recorded block number\r
+ //\r
+ *LastRecordedBlock = LastAvdpBlockNum;\r
+ Status = EFI_SUCCESS;\r
+ break;\r
}\r
}\r
- //\r
- // No AVDP found.\r
- //\r
- return EFI_VOLUME_CORRUPTED;\r
+\r
+Out_Free:\r
+ FreePool (AnchorPoints);\r
+ return Status;\r
}\r
\r
/**\r
- Check if block device supports a valid UDF file system as specified by OSTA\r
- Universal Disk Format Specification 2.60.\r
+ Find UDF volume identifiers in a Volume Recognition Sequence.\r
\r
- @param[in] BlockIo BlockIo interface.\r
- @param[in] DiskIo DiskIo interface.\r
+ @param[in] BlockIo BlockIo interface.\r
+ @param[in] DiskIo DiskIo interface.\r
\r
- @retval EFI_SUCCESS UDF file system found.\r
- @retval EFI_UNSUPPORTED UDF file system not found.\r
- @retval EFI_NO_MEDIA The device has no media.\r
- @retval EFI_DEVICE_ERROR The device reported an error.\r
- @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
- @retval EFI_OUT_OF_RESOURCES The scan was not successful due to lack of\r
- resources.\r
+ @retval EFI_SUCCESS UDF volume identifiers were found.\r
+ @retval EFI_NOT_FOUND UDF volume identifiers were not found.\r
+ @retval other Failed to perform disk I/O.\r
\r
**/\r
EFI_STATUS\r
-SupportUdfFileSystem (\r
+FindUdfVolumeIdentifiers (\r
IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
IN EFI_DISK_IO_PROTOCOL *DiskIo\r
)\r
UINT64 EndDiskOffset;\r
CDROM_VOLUME_DESCRIPTOR VolDescriptor;\r
CDROM_VOLUME_DESCRIPTOR TerminatingVolDescriptor;\r
- UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER AnchorPoint;\r
\r
ZeroMem ((VOID *)&TerminatingVolDescriptor, sizeof (CDROM_VOLUME_DESCRIPTOR));\r
\r
(CompareMem ((VOID *)&VolDescriptor,\r
(VOID *)&TerminatingVolDescriptor,\r
sizeof (CDROM_VOLUME_DESCRIPTOR)) == 0)) {\r
- return EFI_UNSUPPORTED;\r
+ return EFI_NOT_FOUND;\r
}\r
}\r
\r
//\r
Offset += UDF_LOGICAL_SECTOR_SIZE;\r
if (Offset >= EndDiskOffset) {\r
- return EFI_UNSUPPORTED;\r
+ return EFI_NOT_FOUND;\r
}\r
\r
Status = DiskIo->ReadDisk (\r
(CompareMem ((VOID *)VolDescriptor.Unknown.Id,\r
(VOID *)UDF_NSR3_IDENTIFIER,\r
sizeof (VolDescriptor.Unknown.Id)) != 0)) {\r
- return EFI_UNSUPPORTED;\r
+ return EFI_NOT_FOUND;\r
}\r
\r
//\r
//\r
Offset += UDF_LOGICAL_SECTOR_SIZE;\r
if (Offset >= EndDiskOffset) {\r
- return EFI_UNSUPPORTED;\r
+ return EFI_NOT_FOUND;\r
}\r
\r
Status = DiskIo->ReadDisk (\r
if (CompareMem ((VOID *)VolDescriptor.Unknown.Id,\r
(VOID *)UDF_TEA_IDENTIFIER,\r
sizeof (VolDescriptor.Unknown.Id)) != 0) {\r
- return EFI_UNSUPPORTED;\r
+ return EFI_NOT_FOUND;\r
}\r
\r
- Status = FindAnchorVolumeDescriptorPointer (BlockIo, DiskIo, &AnchorPoint);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Check if Logical Volume Descriptor is supported by current EDK2 UDF file\r
+ system implementation.\r
+\r
+ @param[in] LogicalVolDesc Logical Volume Descriptor pointer.\r
+\r
+ @retval TRUE Logical Volume Descriptor is supported.\r
+ @retval FALSE Logical Volume Descriptor is not supported.\r
+\r
+**/\r
+BOOLEAN\r
+IsLogicalVolumeDescriptorSupported (\r
+ UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc\r
+ )\r
+{\r
+ //\r
+ // Check for a valid UDF revision range\r
+ //\r
+ switch (LogicalVolDesc->DomainIdentifier.Suffix.Domain.UdfRevision) {\r
+ case 0x0102:\r
+ case 0x0150:\r
+ case 0x0200:\r
+ case 0x0201:\r
+ case 0x0250:\r
+ case 0x0260:\r
+ break;\r
+ default:\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Check for a single Partition Map\r
+ //\r
+ if (LogicalVolDesc->NumberOfPartitionMaps > 1) {\r
+ return FALSE;\r
+ }\r
+ //\r
+ // UDF 1.02 revision supports only Type 1 (Physical) partitions, but\r
+ // let's check it any way.\r
+ //\r
+ // PartitionMap[0] -> type\r
+ // PartitionMap[1] -> length (in bytes)\r
+ //\r
+ if (LogicalVolDesc->PartitionMaps[0] != 1 ||\r
+ LogicalVolDesc->PartitionMaps[1] != 6) {\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Find UDF logical volume location and whether it is supported by current EDK2\r
+ UDF file system implementation.\r
+\r
+ @param[in] BlockIo BlockIo interface.\r
+ @param[in] DiskIo DiskIo interface.\r
+ @param[in] AnchorPoint Anchor volume descriptor pointer.\r
+ @param[in] LastRecordedBlock Last recorded block in media.\r
+ @param[out] MainVdsStartBlock Main VDS starting block number.\r
+ @param[out] MainVdsEndBlock Main VDS ending block number.\r
+\r
+ @retval EFI_SUCCESS UDF logical volume was found.\r
+ @retval EFI_VOLUME_CORRUPTED UDF file system structures are corrupted.\r
+ @retval EFI_UNSUPPORTED UDF logical volume is not supported.\r
+ @retval other Failed to perform disk I/O.\r
+\r
+**/\r
+EFI_STATUS\r
+FindLogicalVolumeLocation (\r
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
+ IN UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoint,\r
+ IN EFI_LBA LastRecordedBlock,\r
+ OUT UINT64 *MainVdsStartBlock,\r
+ OUT UINT64 *MainVdsEndBlock\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 BlockSize;\r
+ UDF_EXTENT_AD *ExtentAd;\r
+ UINT64 SeqBlocksNum;\r
+ UINT64 SeqStartBlock;\r
+ UINT64 GuardMainVdsStartBlock;\r
+ VOID *Buffer;\r
+ UINT64 SeqEndBlock;\r
+ BOOLEAN StopSequence;\r
+ UINTN LvdsCount;\r
+ UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc;\r
+ UDF_DESCRIPTOR_TAG *DescriptorTag;\r
+\r
+ BlockSize = BlockIo->Media->BlockSize;\r
+ ExtentAd = &AnchorPoint->MainVolumeDescriptorSequenceExtent;\r
+\r
+ //\r
+ // UDF 2.60, 2.2.3.1 struct MainVolumeDescriptorSequenceExtent\r
+ //\r
+ // The Main Volume Descriptor Sequence Extent shall have a minimum length of\r
+ // 16 logical sectors.\r
+ //\r
+ // Also make sure it does not exceed maximum number of blocks in the disk.\r
+ //\r
+ SeqBlocksNum = DivU64x32 ((UINT64)ExtentAd->ExtentLength, BlockSize);\r
+ if (SeqBlocksNum < 16 || (EFI_LBA)SeqBlocksNum > LastRecordedBlock + 1) {\r
+ return EFI_VOLUME_CORRUPTED;\r
+ }\r
+\r
+ //\r
+ // Check for valid Volume Descriptor Sequence starting block number\r
+ //\r
+ SeqStartBlock = (UINT64)ExtentAd->ExtentLocation;\r
+ if (SeqStartBlock > LastRecordedBlock ||\r
+ SeqStartBlock + SeqBlocksNum - 1 > LastRecordedBlock) {\r
+ return EFI_VOLUME_CORRUPTED;\r
+ }\r
+\r
+ GuardMainVdsStartBlock = SeqStartBlock;\r
+\r
+ //\r
+ // Allocate buffer for reading disk blocks\r
+ //\r
+ Buffer = AllocateZeroPool ((UINTN)BlockSize);\r
+ if (Buffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ SeqEndBlock = SeqStartBlock + SeqBlocksNum;\r
+ StopSequence = FALSE;\r
+ LvdsCount = 0;\r
+ Status = EFI_VOLUME_CORRUPTED;\r
+ //\r
+ // Start Main Volume Descriptor Sequence\r
+ //\r
+ for (; SeqStartBlock < SeqEndBlock && !StopSequence; SeqStartBlock++) {\r
+ //\r
+ // Read disk block\r
+ //\r
+ Status = BlockIo->ReadBlocks (\r
+ BlockIo,\r
+ BlockIo->Media->MediaId,\r
+ SeqStartBlock,\r
+ BlockSize,\r
+ Buffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Out_Free;\r
+ }\r
+\r
+ DescriptorTag = Buffer;\r
+\r
+ //\r
+ // ECMA 167, 8.4.1 Contents of a Volume Descriptor Sequence\r
+ //\r
+ // - A Volume Descriptor Sequence shall contain one or more Primary Volume\r
+ // Descriptors.\r
+ // - A Volume Descriptor Sequence shall contain zero or more Implementation\r
+ // Use Volume Descriptors.\r
+ // - A Volume Descriptor Sequence shall contain zero or more Partition\r
+ // Descriptors.\r
+ // - A Volume Descriptor Sequence shall contain zero or more Logical Volume\r
+ // Descriptors.\r
+ // - A Volume Descriptor Sequence shall contain zero or more Unallocated\r
+ // Space Descriptors.\r
+ //\r
+ switch (DescriptorTag->TagIdentifier) {\r
+ case UdfPrimaryVolumeDescriptor:\r
+ case UdfImplemenationUseVolumeDescriptor:\r
+ case UdfPartitionDescriptor:\r
+ case UdfUnallocatedSpaceDescriptor:\r
+ break;\r
+\r
+ case UdfLogicalVolumeDescriptor:\r
+ LogicalVolDesc = Buffer;\r
+\r
+ //\r
+ // Check for existence of a single LVD and whether it is supported by\r
+ // current EDK2 UDF file system implementation.\r
+ //\r
+ if (++LvdsCount > 1 ||\r
+ !IsLogicalVolumeDescriptorSupported (LogicalVolDesc)) {\r
+ Status = EFI_UNSUPPORTED;\r
+ StopSequence = TRUE;\r
+ }\r
+\r
+ break;\r
+\r
+ case UdfTerminatingDescriptor:\r
+ //\r
+ // Stop the sequence when we find a Terminating Descriptor\r
+ // (aka Unallocated Sector), se we don't have to walk all the unallocated\r
+ // area unnecessarily.\r
+ //\r
+ StopSequence = TRUE;\r
+ break;\r
+\r
+ default:\r
+ //\r
+ // An invalid Volume Descriptor has been found in the sequece. Volume is\r
+ // corrupted.\r
+ //\r
+ Status = EFI_VOLUME_CORRUPTED;\r
+ goto Out_Free;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Check if LVD was found\r
+ //\r
+ if (!EFI_ERROR (Status) && LvdsCount == 1) {\r
+ *MainVdsStartBlock = GuardMainVdsStartBlock;\r
+ //\r
+ // We do not need to read either LVD or PD descriptors to know the last\r
+ // valid block in the found UDF file system. It's already\r
+ // LastRecordedBlock.\r
+ //\r
+ *MainVdsEndBlock = LastRecordedBlock;\r
+\r
+ Status = EFI_SUCCESS;\r
+ }\r
+\r
+Out_Free:\r
+ //\r
+ // Free block read buffer\r
+ //\r
+ FreePool (Buffer);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Find a supported UDF file system in block device.\r
+\r
+ @attention This is boundary function that may receive untrusted input.\r
+ @attention The input is from Partition.\r
+\r
+ The CD/DVD media is the external input, so this routine will do basic\r
+ validation for the media.\r
+\r
+ @param[in] BlockIo BlockIo interface.\r
+ @param[in] DiskIo DiskIo interface.\r
+ @param[out] StartingLBA UDF file system starting LBA.\r
+ @param[out] EndingLBA UDF file system starting LBA.\r
+\r
+ @retval EFI_SUCCESS UDF file system was found.\r
+ @retval other UDF file system was not found.\r
+\r
+**/\r
+EFI_STATUS\r
+FindUdfFileSystem (\r
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
+ OUT EFI_LBA *StartingLBA,\r
+ OUT EFI_LBA *EndingLBA\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER AnchorPoint;\r
+ EFI_LBA LastRecordedBlock;\r
+\r
+ //\r
+ // Find UDF volume identifiers\r
+ //\r
+ Status = FindUdfVolumeIdentifiers (BlockIo, DiskIo);\r
if (EFI_ERROR (Status)) {\r
- return EFI_UNSUPPORTED;\r
+ return Status;\r
}\r
\r
- return EFI_SUCCESS;\r
+ //\r
+ // Find Anchor Volume Descriptor Pointer\r
+ //\r
+ Status = FindAnchorVolumeDescriptorPointer (\r
+ BlockIo,\r
+ DiskIo,\r
+ &AnchorPoint,\r
+ &LastRecordedBlock\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Find Logical Volume location\r
+ //\r
+ Status = FindLogicalVolumeLocation (\r
+ BlockIo,\r
+ DiskIo,\r
+ &AnchorPoint,\r
+ LastRecordedBlock,\r
+ (UINT64 *)StartingLBA,\r
+ (UINT64 *)EndingLBA\r
+ );\r
+\r
+ return Status;\r
}\r
\r
/**\r
UINT32 RemainderByMediaBlockSize;\r
EFI_STATUS Status;\r
EFI_BLOCK_IO_MEDIA *Media;\r
- EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;\r
- EFI_GUID *VendorDefinedGuid;\r
- EFI_GUID UdfDevPathGuid = EFI_UDF_DEVICE_PATH_GUID;\r
EFI_PARTITION_INFO_PROTOCOL PartitionInfo;\r
+ EFI_LBA StartingLBA;\r
+ EFI_LBA EndingLBA;\r
+ BOOLEAN ChildCreated;\r
\r
Media = BlockIo->Media;\r
+ ChildCreated = FALSE;\r
\r
//\r
// Check if UDF logical block size is multiple of underlying device block size\r
return EFI_NOT_FOUND;\r
}\r
\r
- DevicePathNode = DevicePath;\r
- while (!IsDevicePathEnd (DevicePathNode)) {\r
- //\r
- // Do not allow checking for UDF file systems in CDROM "El Torito"\r
- // partitions, and skip duplicate installation of UDF file system child\r
- // nodes.\r
- //\r
- if (DevicePathType (DevicePathNode) == MEDIA_DEVICE_PATH) {\r
- if (DevicePathSubType (DevicePathNode) == MEDIA_CDROM_DP) {\r
- return EFI_NOT_FOUND;\r
- }\r
- if (DevicePathSubType (DevicePathNode) == MEDIA_VENDOR_DP) {\r
- VendorDefinedGuid = (EFI_GUID *)((UINTN)DevicePathNode +\r
- OFFSET_OF (VENDOR_DEVICE_PATH, Guid));\r
- if (CompareGuid (VendorDefinedGuid, &UdfDevPathGuid)) {\r
- return EFI_NOT_FOUND;\r
- }\r
- }\r
- }\r
- //\r
- // Try next device path node\r
- //\r
- DevicePathNode = NextDevicePathNode (DevicePathNode);\r
+ //\r
+ // Detect El Torito feature first.\r
+ // And always continue to search for UDF.\r
+ //\r
+ Status = PartitionInstallElToritoChildHandles (\r
+ This,\r
+ Handle,\r
+ DiskIo,\r
+ DiskIo2,\r
+ BlockIo,\r
+ BlockIo2,\r
+ DevicePath\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_INFO, "PartitionDxe: El Torito standard found on handle 0x%p.\n", Handle));\r
+ ChildCreated = TRUE;\r
}\r
\r
//\r
- // Check if block device supports an UDF file system\r
+ // Search for an UDF file system on block device\r
//\r
- Status = SupportUdfFileSystem (BlockIo, DiskIo);\r
+ Status = FindUdfFileSystem (BlockIo, DiskIo, &StartingLBA, &EndingLBA);\r
if (EFI_ERROR (Status)) {\r
- return EFI_NOT_FOUND;\r
+ return (ChildCreated ? EFI_SUCCESS : EFI_NOT_FOUND);\r
}\r
\r
//\r
DevicePath,\r
(EFI_DEVICE_PATH_PROTOCOL *)&gUdfDevicePath,\r
&PartitionInfo,\r
- 0,\r
- Media->LastBlock,\r
- Media->BlockSize\r
+ StartingLBA,\r
+ EndingLBA,\r
+ Media->BlockSize,\r
+ NULL\r
);\r
- if (!EFI_ERROR (Status)) {\r
- Status = EFI_NOT_FOUND;\r
+ if (EFI_ERROR (Status)) {\r
+ return (ChildCreated ? EFI_SUCCESS : Status);\r
}\r
\r
- return Status;\r
+ return EFI_SUCCESS;\r
}\r