2 Scan for an UDF file system on a formatted media.
4 Caution: This file requires additional review when modified.
5 This driver will have external input - CD/DVD media.
6 This external input must be validated carefully to avoid security issue like
7 buffer overflow, integer overflow.
9 FindUdfFileSystem() routine will consume the media properties and do basic
12 Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
13 Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
14 Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
16 SPDX-License-Identifier: BSD-2-Clause-Patent
19 #include "Partition.h"
21 #define MAX_CORRECTION_BLOCKS_NUM 512u
24 // C5BD4D42-1A76-4996-8956-73CDA326CD0A
26 #define EFI_UDF_DEVICE_PATH_GUID \
27 { 0xC5BD4D42, 0x1A76, 0x4996, \
28 { 0x89, 0x56, 0x73, 0xCD, 0xA3, 0x26, 0xCD, 0x0A } \
32 VENDOR_DEVICE_PATH DevicePath
;
33 EFI_DEVICE_PATH_PROTOCOL End
;
37 // Vendor-Defined Device Path GUID for UDF file system
39 EFI_GUID gUdfDevPathGuid
= EFI_UDF_DEVICE_PATH_GUID
;
42 // Vendor-Defined Media Device Path for UDF file system
44 UDF_DEVICE_PATH gUdfDevicePath
= {
46 { MEDIA_DEVICE_PATH
, MEDIA_VENDOR_DP
,
47 { sizeof (VENDOR_DEVICE_PATH
), 0 }
49 EFI_UDF_DEVICE_PATH_GUID
51 { END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
,
52 { sizeof (EFI_DEVICE_PATH_PROTOCOL
), 0 }
57 Find the anchor volume descriptor pointer.
59 @param[in] BlockIo BlockIo interface.
60 @param[in] DiskIo DiskIo interface.
61 @param[out] AnchorPoint Anchor volume descriptor pointer.
62 @param[out] LastRecordedBlock Last recorded block.
64 @retval EFI_SUCCESS Anchor volume descriptor pointer found.
65 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
66 @retval other Anchor volume descriptor pointer not found.
70 FindAnchorVolumeDescriptorPointer (
71 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
72 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
73 OUT UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
*AnchorPoint
,
74 OUT EFI_LBA
*LastRecordedBlock
80 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
83 UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
*AnchorPoints
;
85 UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
*AnchorPointPtr
;
86 EFI_LBA LastAvdpBlockNum
;
89 // UDF 2.60, 2.2.3 Anchor Volume Descriptor Pointer
91 // An Anchor Volume Descriptor Pointer structure shall be recorded in at
92 // least 2 of the following 3 locations on the media: Logical Sector 256,
93 // N - 256 or N, where N is the last *addressable* sector of a volume.
95 // To figure out what logical sector N is, the SCSI commands READ CAPACITY and
96 // READ TRACK INFORMATION are used, however many drives or medias report their
97 // "last recorded block" wrongly. Although, READ CAPACITY returns the last
98 // readable data block but there might be unwritten blocks, which are located
99 // outside any track and therefore AVDP will not be found at block N.
101 // That said, we define a magic number of 512 blocks to be used as correction
102 // when attempting to find AVDP and define last block number.
104 BlockSize
= BlockIo
->Media
->BlockSize
;
105 EndLBA
= BlockIo
->Media
->LastBlock
;
106 *LastRecordedBlock
= EndLBA
;
110 // Check if the block size of the underlying media can hold the data of an
111 // Anchor Volume Descriptor Pointer
113 if (BlockSize
< sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
)) {
116 "%a: Media block size 0x%x unable to hold an AVDP.\n",
120 return EFI_UNSUPPORTED
;
124 // Find AVDP at block 256
126 Status
= DiskIo
->ReadDisk (
128 BlockIo
->Media
->MediaId
,
129 MultU64x32 (256, BlockSize
),
130 sizeof (*AnchorPoint
),
133 if (EFI_ERROR (Status
)) {
137 DescriptorTag
= &AnchorPoint
->DescriptorTag
;
140 // Check if read block is a valid AVDP descriptor
142 if (DescriptorTag
->TagIdentifier
== UdfAnchorVolumeDescriptorPointer
) {
143 DEBUG ((DEBUG_INFO
, "%a: found AVDP at block %d\n", __FUNCTION__
, 256));
148 // Find AVDP at block N - 256
150 Status
= DiskIo
->ReadDisk (
152 BlockIo
->Media
->MediaId
,
153 MultU64x32 ((UINT64
)EndLBA
- 256, BlockSize
),
154 sizeof (*AnchorPoint
),
157 if (EFI_ERROR (Status
)) {
162 // Check if read block is a valid AVDP descriptor
164 if ((DescriptorTag
->TagIdentifier
== UdfAnchorVolumeDescriptorPointer
) &&
169 "%a: found AVDP at block %Ld\n",
177 // Check if at least one AVDP was found in previous locations
179 if (AvdpsCount
== 0) {
180 return EFI_VOLUME_CORRUPTED
;
184 // Find AVDP at block N
186 Status
= DiskIo
->ReadDisk (
188 BlockIo
->Media
->MediaId
,
189 MultU64x32 ((UINT64
)EndLBA
, BlockSize
),
190 sizeof (*AnchorPoint
),
193 if (EFI_ERROR (Status
)) {
198 // Check if read block is a valid AVDP descriptor
200 if (DescriptorTag
->TagIdentifier
== UdfAnchorVolumeDescriptorPointer
) {
205 // No AVDP found at block N. Possibly drive/media returned bad last recorded
206 // block, or it is part of unwritten data blocks and outside any track.
208 // Search backwards for an AVDP from block N-1 through
209 // N-MAX_CORRECTION_BLOCKS_NUM. If any AVDP is found, then correct last block
210 // number for the new UDF partition child handle.
212 Size
= MAX_CORRECTION_BLOCKS_NUM
* BlockSize
;
214 AnchorPoints
= AllocateZeroPool (Size
);
215 if (AnchorPoints
== NULL
) {
216 return EFI_OUT_OF_RESOURCES
;
220 // Read consecutive MAX_CORRECTION_BLOCKS_NUM disk blocks
222 Status
= DiskIo
->ReadDisk (
224 BlockIo
->Media
->MediaId
,
225 MultU64x32 ((UINT64
)EndLBA
- MAX_CORRECTION_BLOCKS_NUM
, BlockSize
),
229 if (EFI_ERROR (Status
)) {
233 Status
= EFI_VOLUME_CORRUPTED
;
236 // Search for AVDP from blocks N-1 through N-MAX_CORRECTION_BLOCKS_NUM
238 for (Index
= MAX_CORRECTION_BLOCKS_NUM
- 2; Index
>= 0; Index
--) {
239 AnchorPointPtr
= (VOID
*)((UINTN
)AnchorPoints
+ Index
* BlockSize
);
241 DescriptorTag
= &AnchorPointPtr
->DescriptorTag
;
244 // Check if read block is a valid AVDP descriptor
246 if (DescriptorTag
->TagIdentifier
== UdfAnchorVolumeDescriptorPointer
) {
248 // Calculate last recorded block number
250 LastAvdpBlockNum
= EndLBA
- (MAX_CORRECTION_BLOCKS_NUM
- Index
);
253 "%a: found AVDP at block %Ld\n",
259 "%a: correcting last block from %Ld to %Ld\n",
265 // Save read AVDP from last block
267 CopyMem (AnchorPoint
, AnchorPointPtr
, sizeof (*AnchorPointPtr
));
269 // Set last recorded block number
271 *LastRecordedBlock
= LastAvdpBlockNum
;
272 Status
= EFI_SUCCESS
;
278 FreePool (AnchorPoints
);
283 Find UDF volume identifiers in a Volume Recognition Sequence.
285 @param[in] BlockIo BlockIo interface.
286 @param[in] DiskIo DiskIo interface.
288 @retval EFI_SUCCESS UDF volume identifiers were found.
289 @retval EFI_NOT_FOUND UDF volume identifiers were not found.
290 @retval other Failed to perform disk I/O.
294 FindUdfVolumeIdentifiers (
295 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
296 IN EFI_DISK_IO_PROTOCOL
*DiskIo
301 UINT64 EndDiskOffset
;
302 CDROM_VOLUME_DESCRIPTOR VolDescriptor
;
303 CDROM_VOLUME_DESCRIPTOR TerminatingVolDescriptor
;
305 ZeroMem ((VOID
*)&TerminatingVolDescriptor
, sizeof (CDROM_VOLUME_DESCRIPTOR
));
308 // Start Volume Recognition Sequence
310 EndDiskOffset
= MultU64x32 (
311 BlockIo
->Media
->LastBlock
,
312 BlockIo
->Media
->BlockSize
315 for (Offset
= UDF_VRS_START_OFFSET
; Offset
< EndDiskOffset
;
316 Offset
+= UDF_LOGICAL_SECTOR_SIZE
)
319 // Check if block device has a Volume Structure Descriptor and an Extended
322 Status
= DiskIo
->ReadDisk (
324 BlockIo
->Media
->MediaId
,
326 sizeof (CDROM_VOLUME_DESCRIPTOR
),
327 (VOID
*)&VolDescriptor
329 if (EFI_ERROR (Status
)) {
334 (VOID
*)VolDescriptor
.Unknown
.Id
,
335 (VOID
*)UDF_BEA_IDENTIFIER
,
336 sizeof (VolDescriptor
.Unknown
.Id
)
343 (VOID
*)VolDescriptor
.Unknown
.Id
,
345 sizeof (VolDescriptor
.Unknown
.Id
)
348 (VOID
*)&VolDescriptor
,
349 (VOID
*)&TerminatingVolDescriptor
,
350 sizeof (CDROM_VOLUME_DESCRIPTOR
)
353 return EFI_NOT_FOUND
;
358 // Look for "NSR0{2,3}" identifiers in the Extended Area.
360 Offset
+= UDF_LOGICAL_SECTOR_SIZE
;
361 if (Offset
>= EndDiskOffset
) {
362 return EFI_NOT_FOUND
;
365 Status
= DiskIo
->ReadDisk (
367 BlockIo
->Media
->MediaId
,
369 sizeof (CDROM_VOLUME_DESCRIPTOR
),
370 (VOID
*)&VolDescriptor
372 if (EFI_ERROR (Status
)) {
377 (VOID
*)VolDescriptor
.Unknown
.Id
,
378 (VOID
*)UDF_NSR2_IDENTIFIER
,
379 sizeof (VolDescriptor
.Unknown
.Id
)
382 (VOID
*)VolDescriptor
.Unknown
.Id
,
383 (VOID
*)UDF_NSR3_IDENTIFIER
,
384 sizeof (VolDescriptor
.Unknown
.Id
)
387 return EFI_NOT_FOUND
;
391 // Look for "TEA01" identifier in the Extended Area
393 Offset
+= UDF_LOGICAL_SECTOR_SIZE
;
394 if (Offset
>= EndDiskOffset
) {
395 return EFI_NOT_FOUND
;
398 Status
= DiskIo
->ReadDisk (
400 BlockIo
->Media
->MediaId
,
402 sizeof (CDROM_VOLUME_DESCRIPTOR
),
403 (VOID
*)&VolDescriptor
405 if (EFI_ERROR (Status
)) {
410 (VOID
*)VolDescriptor
.Unknown
.Id
,
411 (VOID
*)UDF_TEA_IDENTIFIER
,
412 sizeof (VolDescriptor
.Unknown
.Id
)
415 return EFI_NOT_FOUND
;
422 Check if Logical Volume Descriptor is supported by current EDK2 UDF file
423 system implementation.
425 @param[in] LogicalVolDesc Logical Volume Descriptor pointer.
427 @retval TRUE Logical Volume Descriptor is supported.
428 @retval FALSE Logical Volume Descriptor is not supported.
432 IsLogicalVolumeDescriptorSupported (
433 UDF_LOGICAL_VOLUME_DESCRIPTOR
*LogicalVolDesc
437 // Check for a valid UDF revision range
439 switch (LogicalVolDesc
->DomainIdentifier
.Suffix
.Domain
.UdfRevision
) {
452 // Check for a single Partition Map
454 if (LogicalVolDesc
->NumberOfPartitionMaps
> 1) {
459 // UDF 1.02 revision supports only Type 1 (Physical) partitions, but
460 // let's check it any way.
462 // PartitionMap[0] -> type
463 // PartitionMap[1] -> length (in bytes)
465 if ((LogicalVolDesc
->PartitionMaps
[0] != 1) ||
466 (LogicalVolDesc
->PartitionMaps
[1] != 6))
475 Find UDF logical volume location and whether it is supported by current EDK2
476 UDF file system implementation.
478 @param[in] BlockIo BlockIo interface.
479 @param[in] DiskIo DiskIo interface.
480 @param[in] AnchorPoint Anchor volume descriptor pointer.
481 @param[in] LastRecordedBlock Last recorded block in media.
482 @param[out] MainVdsStartBlock Main VDS starting block number.
483 @param[out] MainVdsEndBlock Main VDS ending block number.
485 @retval EFI_SUCCESS UDF logical volume was found.
486 @retval EFI_VOLUME_CORRUPTED UDF file system structures are corrupted.
487 @retval EFI_UNSUPPORTED UDF logical volume is not supported.
488 @retval other Failed to perform disk I/O.
492 FindLogicalVolumeLocation (
493 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
494 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
495 IN UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
*AnchorPoint
,
496 IN EFI_LBA LastRecordedBlock
,
497 OUT UINT64
*MainVdsStartBlock
,
498 OUT UINT64
*MainVdsEndBlock
503 UDF_EXTENT_AD
*ExtentAd
;
505 UINT64 SeqStartBlock
;
506 UINT64 GuardMainVdsStartBlock
;
509 BOOLEAN StopSequence
;
511 UDF_LOGICAL_VOLUME_DESCRIPTOR
*LogicalVolDesc
;
512 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
514 BlockSize
= BlockIo
->Media
->BlockSize
;
515 ExtentAd
= &AnchorPoint
->MainVolumeDescriptorSequenceExtent
;
518 // UDF 2.60, 2.2.3.1 struct MainVolumeDescriptorSequenceExtent
520 // The Main Volume Descriptor Sequence Extent shall have a minimum length of
521 // 16 logical sectors.
523 // Also make sure it does not exceed maximum number of blocks in the disk.
525 SeqBlocksNum
= DivU64x32 ((UINT64
)ExtentAd
->ExtentLength
, BlockSize
);
526 if ((SeqBlocksNum
< 16) || ((EFI_LBA
)SeqBlocksNum
> LastRecordedBlock
+ 1)) {
527 return EFI_VOLUME_CORRUPTED
;
531 // Check for valid Volume Descriptor Sequence starting block number
533 SeqStartBlock
= (UINT64
)ExtentAd
->ExtentLocation
;
534 if ((SeqStartBlock
> LastRecordedBlock
) ||
535 (SeqStartBlock
+ SeqBlocksNum
- 1 > LastRecordedBlock
))
537 return EFI_VOLUME_CORRUPTED
;
540 GuardMainVdsStartBlock
= SeqStartBlock
;
543 // Allocate buffer for reading disk blocks
545 Buffer
= AllocateZeroPool ((UINTN
)BlockSize
);
546 if (Buffer
== NULL
) {
547 return EFI_OUT_OF_RESOURCES
;
550 SeqEndBlock
= SeqStartBlock
+ SeqBlocksNum
;
551 StopSequence
= FALSE
;
553 Status
= EFI_VOLUME_CORRUPTED
;
555 // Start Main Volume Descriptor Sequence
557 for ( ; SeqStartBlock
< SeqEndBlock
&& !StopSequence
; SeqStartBlock
++) {
561 Status
= BlockIo
->ReadBlocks (
563 BlockIo
->Media
->MediaId
,
568 if (EFI_ERROR (Status
)) {
572 DescriptorTag
= Buffer
;
575 // ECMA 167, 8.4.1 Contents of a Volume Descriptor Sequence
577 // - A Volume Descriptor Sequence shall contain one or more Primary Volume
579 // - A Volume Descriptor Sequence shall contain zero or more Implementation
580 // Use Volume Descriptors.
581 // - A Volume Descriptor Sequence shall contain zero or more Partition
583 // - A Volume Descriptor Sequence shall contain zero or more Logical Volume
585 // - A Volume Descriptor Sequence shall contain zero or more Unallocated
586 // Space Descriptors.
588 switch (DescriptorTag
->TagIdentifier
) {
589 case UdfPrimaryVolumeDescriptor
:
590 case UdfImplemenationUseVolumeDescriptor
:
591 case UdfPartitionDescriptor
:
592 case UdfUnallocatedSpaceDescriptor
:
595 case UdfLogicalVolumeDescriptor
:
596 LogicalVolDesc
= Buffer
;
599 // Check for existence of a single LVD and whether it is supported by
600 // current EDK2 UDF file system implementation.
602 if ((++LvdsCount
> 1) ||
603 !IsLogicalVolumeDescriptorSupported (LogicalVolDesc
))
605 Status
= EFI_UNSUPPORTED
;
611 case UdfTerminatingDescriptor
:
613 // Stop the sequence when we find a Terminating Descriptor
614 // (aka Unallocated Sector), se we don't have to walk all the unallocated
615 // area unnecessarily.
622 // An invalid Volume Descriptor has been found in the sequece. Volume is
625 Status
= EFI_VOLUME_CORRUPTED
;
631 // Check if LVD was found
633 if (!EFI_ERROR (Status
) && (LvdsCount
== 1)) {
634 *MainVdsStartBlock
= GuardMainVdsStartBlock
;
636 // We do not need to read either LVD or PD descriptors to know the last
637 // valid block in the found UDF file system. It's already
638 // LastRecordedBlock.
640 *MainVdsEndBlock
= LastRecordedBlock
;
642 Status
= EFI_SUCCESS
;
647 // Free block read buffer
655 Find a supported UDF file system in block device.
657 @attention This is boundary function that may receive untrusted input.
658 @attention The input is from Partition.
660 The CD/DVD media is the external input, so this routine will do basic
661 validation for the media.
663 @param[in] BlockIo BlockIo interface.
664 @param[in] DiskIo DiskIo interface.
665 @param[out] StartingLBA UDF file system starting LBA.
666 @param[out] EndingLBA UDF file system starting LBA.
668 @retval EFI_SUCCESS UDF file system was found.
669 @retval other UDF file system was not found.
674 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
675 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
676 OUT EFI_LBA
*StartingLBA
,
677 OUT EFI_LBA
*EndingLBA
681 UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER AnchorPoint
;
682 EFI_LBA LastRecordedBlock
;
685 // Find UDF volume identifiers
687 Status
= FindUdfVolumeIdentifiers (BlockIo
, DiskIo
);
688 if (EFI_ERROR (Status
)) {
693 // Find Anchor Volume Descriptor Pointer
695 Status
= FindAnchorVolumeDescriptorPointer (
701 if (EFI_ERROR (Status
)) {
706 // Find Logical Volume location
708 Status
= FindLogicalVolumeLocation (
713 (UINT64
*)StartingLBA
,
721 Install child handles if the Handle supports UDF/ECMA-167 volume format.
723 @param[in] This Calling context.
724 @param[in] Handle Parent Handle.
725 @param[in] DiskIo Parent DiskIo interface.
726 @param[in] DiskIo2 Parent DiskIo2 interface.
727 @param[in] BlockIo Parent BlockIo interface.
728 @param[in] BlockIo2 Parent BlockIo2 interface.
729 @param[in] DevicePath Parent Device Path
732 @retval EFI_SUCCESS Child handle(s) was added.
733 @retval EFI_MEDIA_CHANGED Media changed Detected.
734 @retval other no child handle was added.
738 PartitionInstallUdfChildHandles (
739 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
740 IN EFI_HANDLE Handle
,
741 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
742 IN EFI_DISK_IO2_PROTOCOL
*DiskIo2
,
743 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
744 IN EFI_BLOCK_IO2_PROTOCOL
*BlockIo2
,
745 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
748 UINT32 RemainderByMediaBlockSize
;
750 EFI_BLOCK_IO_MEDIA
*Media
;
751 EFI_PARTITION_INFO_PROTOCOL PartitionInfo
;
754 BOOLEAN ChildCreated
;
756 Media
= BlockIo
->Media
;
757 ChildCreated
= FALSE
;
760 // Check if UDF logical block size is multiple of underlying device block size
763 UDF_LOGICAL_SECTOR_SIZE
, // Dividend
764 Media
->BlockSize
, // Divisor
765 &RemainderByMediaBlockSize
// Remainder
767 if (RemainderByMediaBlockSize
!= 0) {
768 return EFI_NOT_FOUND
;
772 // Detect El Torito feature first.
773 // And always continue to search for UDF.
775 Status
= PartitionInstallElToritoChildHandles (
784 if (!EFI_ERROR (Status
)) {
785 DEBUG ((DEBUG_INFO
, "PartitionDxe: El Torito standard found on handle 0x%p.\n", Handle
));
790 // Search for an UDF file system on block device
792 Status
= FindUdfFileSystem (BlockIo
, DiskIo
, &StartingLBA
, &EndingLBA
);
793 if (EFI_ERROR (Status
)) {
794 return (ChildCreated
? EFI_SUCCESS
: EFI_NOT_FOUND
);
798 // Create Partition Info protocol for UDF file system
800 ZeroMem (&PartitionInfo
, sizeof (EFI_PARTITION_INFO_PROTOCOL
));
801 PartitionInfo
.Revision
= EFI_PARTITION_INFO_PROTOCOL_REVISION
;
802 PartitionInfo
.Type
= PARTITION_TYPE_OTHER
;
805 // Install partition child handle for UDF file system
807 Status
= PartitionInstallChildHandle (
815 (EFI_DEVICE_PATH_PROTOCOL
*)&gUdfDevicePath
,
822 if (EFI_ERROR (Status
)) {
823 return (ChildCreated
? EFI_SUCCESS
: Status
);