--- /dev/null
+/** @file\r
+ Scan for an UDF file system on a formatted media.\r
+\r
+ Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>\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
+\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
+**/\r
+\r
+#include "Partition.h"\r
+\r
+//\r
+// C5BD4D42-1A76-4996-8956-73CDA326CD0A\r
+//\r
+#define EFI_UDF_DEVICE_PATH_GUID \\r
+ { 0xC5BD4D42, 0x1A76, 0x4996, \\r
+ { 0x89, 0x56, 0x73, 0xCD, 0xA3, 0x26, 0xCD, 0x0A } \\r
+ }\r
+\r
+typedef struct {\r
+ VENDOR_DEVICE_PATH DevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL End;\r
+} UDF_DEVICE_PATH;\r
+\r
+//\r
+// Vendor-Defined Media Device Path for UDF file system\r
+//\r
+UDF_DEVICE_PATH gUdfDevicePath = {\r
+ { { MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP,\r
+ { sizeof (VENDOR_DEVICE_PATH), 0 } },\r
+ EFI_UDF_DEVICE_PATH_GUID\r
+ },\r
+ { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
+ { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }\r
+ }\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
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 BlockSize = BlockIo->Media->BlockSize;\r
+ EFI_LBA EndLBA = BlockIo->Media->LastBlock;\r
+ EFI_LBA DescriptorLBAs[] = { 256, EndLBA - 256, EndLBA, 512 };\r
+ UINTN Index;\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
+ //\r
+ if (IS_AVDP (AnchorPoint)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ //\r
+ // No AVDP found.\r
+ //\r
+ return EFI_VOLUME_CORRUPTED;\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
+\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
+\r
+**/\r
+EFI_STATUS\r
+SupportUdfFileSystem (\r
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
+ IN EFI_DISK_IO_PROTOCOL *DiskIo\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 Offset;\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
+ //\r
+ // Start Volume Recognition Sequence\r
+ //\r
+ EndDiskOffset = MultU64x32 (BlockIo->Media->LastBlock,\r
+ BlockIo->Media->BlockSize);\r
+\r
+ for (Offset = UDF_VRS_START_OFFSET; Offset < EndDiskOffset;\r
+ Offset += UDF_LOGICAL_SECTOR_SIZE) {\r
+ //\r
+ // Check if block device has a Volume Structure Descriptor and an Extended\r
+ // Area.\r
+ //\r
+ Status = DiskIo->ReadDisk (\r
+ DiskIo,\r
+ BlockIo->Media->MediaId,\r
+ Offset,\r
+ sizeof (CDROM_VOLUME_DESCRIPTOR),\r
+ (VOID *)&VolDescriptor\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (CompareMem ((VOID *)VolDescriptor.Unknown.Id,\r
+ (VOID *)UDF_BEA_IDENTIFIER,\r
+ sizeof (VolDescriptor.Unknown.Id)) == 0) {\r
+ break;\r
+ }\r
+\r
+ if ((CompareMem ((VOID *)VolDescriptor.Unknown.Id,\r
+ (VOID *)CDVOL_ID,\r
+ sizeof (VolDescriptor.Unknown.Id)) != 0) ||\r
+ (CompareMem ((VOID *)&VolDescriptor,\r
+ (VOID *)&TerminatingVolDescriptor,\r
+ sizeof (CDROM_VOLUME_DESCRIPTOR)) == 0)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Look for "NSR0{2,3}" identifiers in the Extended Area.\r
+ //\r
+ Offset += UDF_LOGICAL_SECTOR_SIZE;\r
+ if (Offset >= EndDiskOffset) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Status = DiskIo->ReadDisk (\r
+ DiskIo,\r
+ BlockIo->Media->MediaId,\r
+ Offset,\r
+ sizeof (CDROM_VOLUME_DESCRIPTOR),\r
+ (VOID *)&VolDescriptor\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if ((CompareMem ((VOID *)VolDescriptor.Unknown.Id,\r
+ (VOID *)UDF_NSR2_IDENTIFIER,\r
+ sizeof (VolDescriptor.Unknown.Id)) != 0) &&\r
+ (CompareMem ((VOID *)VolDescriptor.Unknown.Id,\r
+ (VOID *)UDF_NSR3_IDENTIFIER,\r
+ sizeof (VolDescriptor.Unknown.Id)) != 0)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Look for "TEA01" identifier in the Extended Area\r
+ //\r
+ Offset += UDF_LOGICAL_SECTOR_SIZE;\r
+ if (Offset >= EndDiskOffset) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Status = DiskIo->ReadDisk (\r
+ DiskIo,\r
+ BlockIo->Media->MediaId,\r
+ Offset,\r
+ sizeof (CDROM_VOLUME_DESCRIPTOR),\r
+ (VOID *)&VolDescriptor\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (CompareMem ((VOID *)VolDescriptor.Unknown.Id,\r
+ (VOID *)UDF_TEA_IDENTIFIER,\r
+ sizeof (VolDescriptor.Unknown.Id)) != 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Status = FindAnchorVolumeDescriptorPointer (BlockIo, DiskIo, &AnchorPoint);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Install child handles if the Handle supports UDF/ECMA-167 volume format.\r
+\r
+ @param[in] This Calling context.\r
+ @param[in] Handle Parent Handle.\r
+ @param[in] DiskIo Parent DiskIo interface.\r
+ @param[in] DiskIo2 Parent DiskIo2 interface.\r
+ @param[in] BlockIo Parent BlockIo interface.\r
+ @param[in] BlockIo2 Parent BlockIo2 interface.\r
+ @param[in] DevicePath Parent Device Path\r
+\r
+\r
+ @retval EFI_SUCCESS Child handle(s) was added.\r
+ @retval EFI_MEDIA_CHANGED Media changed Detected.\r
+ @retval other no child handle was added.\r
+\r
+**/\r
+EFI_STATUS\r
+PartitionInstallUdfChildHandles (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Handle,\r
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,\r
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
+ IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+ )\r
+{\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
+\r
+ Media = BlockIo->Media;\r
+\r
+ //\r
+ // Check if UDF logical block size is multiple of underlying device block size\r
+ //\r
+ if ((UDF_LOGICAL_SECTOR_SIZE % Media->BlockSize) != 0 ||\r
+ Media->BlockSize > UDF_LOGICAL_SECTOR_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
+\r
+ //\r
+ // Check if block device supports an UDF file system\r
+ //\r
+ Status = SupportUdfFileSystem (BlockIo, DiskIo);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // Create Partition Info protocol for UDF file system\r
+ //\r
+ ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));\r
+ PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;\r
+ PartitionInfo.Type = PARTITION_TYPE_OTHER;\r
+\r
+ //\r
+ // Install partition child handle for UDF file system\r
+ //\r
+ Status = PartitionInstallChildHandle (\r
+ This,\r
+ Handle,\r
+ DiskIo,\r
+ DiskIo2,\r
+ BlockIo,\r
+ BlockIo2,\r
+ DevicePath,\r
+ (EFI_DEVICE_PATH_PROTOCOL *)&gUdfDevicePath,\r
+ &PartitionInfo,\r
+ 0,\r
+ Media->LastBlock,\r
+ Media->BlockSize\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = EFI_NOT_FOUND;\r
+ }\r
+\r
+ return Status;\r
+}\r