OUT UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoint\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
+ EFI_LBA DescriptorLBAs[4];\r
+ UINTN Index;\r
+ UDF_DESCRIPTOR_TAG *DescriptorTag;\r
\r
BlockSize = BlockIo->Media->BlockSize;\r
EndLBA = BlockIo->Media->LastBlock;\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
+\r
+ DescriptorTag = &AnchorPoint->DescriptorTag;\r
+\r
//\r
// Check if read LBA has a valid AVDP descriptor.\r
//\r
- if (IS_AVDP (AnchorPoint)) {\r
+ if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) {\r
return EFI_SUCCESS;\r
}\r
}\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
+ 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[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
+ OUT UINT64 *MainVdsStartBlock,\r
+ OUT UINT64 *MainVdsEndBlock\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 BlockSize;\r
+ EFI_LBA LastBlock;\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
+ LastBlock = BlockIo->Media->LastBlock;\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 > LastBlock + 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 > LastBlock ||\r
+ SeqStartBlock + SeqBlocksNum - 1 > LastBlock) {\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 LastBlock.\r
+ //\r
+ *MainVdsEndBlock = LastBlock;\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
+ @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
+\r
+ //\r
+ // Find UDF volume identifiers\r
+ //\r
+ Status = FindUdfVolumeIdentifiers (BlockIo, DiskIo);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
}\r
\r
+ //\r
+ // Find Anchor Volume Descriptor Pointer\r
+ //\r
Status = FindAnchorVolumeDescriptorPointer (BlockIo, DiskIo, &AnchorPoint);\r
if (EFI_ERROR (Status)) {\r
- return EFI_UNSUPPORTED;\r
+ return Status;\r
}\r
\r
- return EFI_SUCCESS;\r
+ //\r
+ // Find Logical Volume location\r
+ //\r
+ Status = FindLogicalVolumeLocation (\r
+ BlockIo,\r
+ DiskIo,\r
+ &AnchorPoint,\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_PARTITION_INFO_PROTOCOL PartitionInfo;\r
+ EFI_LBA StartingLBA;\r
+ EFI_LBA EndingLBA;\r
\r
Media = BlockIo->Media;\r
\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, &gUdfDevPathGuid)) {\r
- return EFI_NOT_FOUND;\r
- }\r
- }\r
- }\r
- //\r
- // Try next device path node\r
- //\r
- DevicePathNode = NextDevicePathNode (DevicePathNode);\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
}\r
DevicePath,\r
(EFI_DEVICE_PATH_PROTOCOL *)&gUdfDevicePath,\r
&PartitionInfo,\r
- 0,\r
- Media->LastBlock,\r
+ StartingLBA,\r
+ EndingLBA,\r
Media->BlockSize\r
);\r
- if (!EFI_ERROR (Status)) {\r
- Status = EFI_NOT_FOUND;\r
- }\r
\r
return Status;\r
}\r