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
= {
45 { { MEDIA_DEVICE_PATH
, MEDIA_VENDOR_DP
,
46 { sizeof (VENDOR_DEVICE_PATH
), 0 } },
47 EFI_UDF_DEVICE_PATH_GUID
49 { END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
,
50 { sizeof (EFI_DEVICE_PATH_PROTOCOL
), 0 }
55 Find the anchor volume descriptor pointer.
57 @param[in] BlockIo BlockIo interface.
58 @param[in] DiskIo DiskIo interface.
59 @param[out] AnchorPoint Anchor volume descriptor pointer.
60 @param[out] LastRecordedBlock Last recorded block.
62 @retval EFI_SUCCESS Anchor volume descriptor pointer found.
63 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
64 @retval other Anchor volume descriptor pointer not found.
68 FindAnchorVolumeDescriptorPointer (
69 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
70 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
71 OUT UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
*AnchorPoint
,
72 OUT EFI_LBA
*LastRecordedBlock
78 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
81 UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
*AnchorPoints
;
83 UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
*AnchorPointPtr
;
84 EFI_LBA LastAvdpBlockNum
;
87 // UDF 2.60, 2.2.3 Anchor Volume Descriptor Pointer
89 // An Anchor Volume Descriptor Pointer structure shall be recorded in at
90 // least 2 of the following 3 locations on the media: Logical Sector 256,
91 // N - 256 or N, where N is the last *addressable* sector of a volume.
93 // To figure out what logical sector N is, the SCSI commands READ CAPACITY and
94 // READ TRACK INFORMATION are used, however many drives or medias report their
95 // "last recorded block" wrongly. Although, READ CAPACITY returns the last
96 // readable data block but there might be unwritten blocks, which are located
97 // outside any track and therefore AVDP will not be found at block N.
99 // That said, we define a magic number of 512 blocks to be used as correction
100 // when attempting to find AVDP and define last block number.
102 BlockSize
= BlockIo
->Media
->BlockSize
;
103 EndLBA
= BlockIo
->Media
->LastBlock
;
104 *LastRecordedBlock
= EndLBA
;
108 // Check if the block size of the underlying media can hold the data of an
109 // Anchor Volume Descriptor Pointer
111 if (BlockSize
< sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
)) {
114 "%a: Media block size 0x%x unable to hold an AVDP.\n",
118 return EFI_UNSUPPORTED
;
122 // Find AVDP at block 256
124 Status
= DiskIo
->ReadDisk (
126 BlockIo
->Media
->MediaId
,
127 MultU64x32 (256, BlockSize
),
128 sizeof (*AnchorPoint
),
131 if (EFI_ERROR (Status
)) {
135 DescriptorTag
= &AnchorPoint
->DescriptorTag
;
138 // Check if read block is a valid AVDP descriptor
140 if (DescriptorTag
->TagIdentifier
== UdfAnchorVolumeDescriptorPointer
) {
141 DEBUG ((DEBUG_INFO
, "%a: found AVDP at block %d\n", __FUNCTION__
, 256));
146 // Find AVDP at block N - 256
148 Status
= DiskIo
->ReadDisk (
150 BlockIo
->Media
->MediaId
,
151 MultU64x32 ((UINT64
)EndLBA
- 256, BlockSize
),
152 sizeof (*AnchorPoint
),
155 if (EFI_ERROR (Status
)) {
160 // Check if read block is a valid AVDP descriptor
162 if (DescriptorTag
->TagIdentifier
== UdfAnchorVolumeDescriptorPointer
&&
164 DEBUG ((DEBUG_INFO
, "%a: found AVDP at block %Ld\n", __FUNCTION__
,
170 // Check if at least one AVDP was found in previous locations
172 if (AvdpsCount
== 0) {
173 return EFI_VOLUME_CORRUPTED
;
177 // Find AVDP at block N
179 Status
= DiskIo
->ReadDisk (
181 BlockIo
->Media
->MediaId
,
182 MultU64x32 ((UINT64
)EndLBA
, BlockSize
),
183 sizeof (*AnchorPoint
),
186 if (EFI_ERROR (Status
)) {
191 // Check if read block is a valid AVDP descriptor
193 if (DescriptorTag
->TagIdentifier
== UdfAnchorVolumeDescriptorPointer
) {
198 // No AVDP found at block N. Possibly drive/media returned bad last recorded
199 // block, or it is part of unwritten data blocks and outside any track.
201 // Search backwards for an AVDP from block N-1 through
202 // N-MAX_CORRECTION_BLOCKS_NUM. If any AVDP is found, then correct last block
203 // number for the new UDF partition child handle.
205 Size
= MAX_CORRECTION_BLOCKS_NUM
* BlockSize
;
207 AnchorPoints
= AllocateZeroPool (Size
);
208 if (AnchorPoints
== NULL
) {
209 return EFI_OUT_OF_RESOURCES
;
213 // Read consecutive MAX_CORRECTION_BLOCKS_NUM disk blocks
215 Status
= DiskIo
->ReadDisk (
217 BlockIo
->Media
->MediaId
,
218 MultU64x32 ((UINT64
)EndLBA
- MAX_CORRECTION_BLOCKS_NUM
, BlockSize
),
222 if (EFI_ERROR (Status
)) {
226 Status
= EFI_VOLUME_CORRUPTED
;
229 // Search for AVDP from blocks N-1 through N-MAX_CORRECTION_BLOCKS_NUM
231 for (Index
= MAX_CORRECTION_BLOCKS_NUM
- 2; Index
>= 0; Index
--) {
232 AnchorPointPtr
= (VOID
*)((UINTN
)AnchorPoints
+ Index
* BlockSize
);
234 DescriptorTag
= &AnchorPointPtr
->DescriptorTag
;
237 // Check if read block is a valid AVDP descriptor
239 if (DescriptorTag
->TagIdentifier
== UdfAnchorVolumeDescriptorPointer
) {
241 // Calculate last recorded block number
243 LastAvdpBlockNum
= EndLBA
- (MAX_CORRECTION_BLOCKS_NUM
- Index
);
244 DEBUG ((DEBUG_WARN
, "%a: found AVDP at block %Ld\n", __FUNCTION__
,
246 DEBUG ((DEBUG_WARN
, "%a: correcting last block from %Ld to %Ld\n",
247 __FUNCTION__
, EndLBA
, LastAvdpBlockNum
));
249 // Save read AVDP from last block
251 CopyMem (AnchorPoint
, AnchorPointPtr
, sizeof (*AnchorPointPtr
));
253 // Set last recorded block number
255 *LastRecordedBlock
= LastAvdpBlockNum
;
256 Status
= EFI_SUCCESS
;
262 FreePool (AnchorPoints
);
267 Find UDF volume identifiers in a Volume Recognition Sequence.
269 @param[in] BlockIo BlockIo interface.
270 @param[in] DiskIo DiskIo interface.
272 @retval EFI_SUCCESS UDF volume identifiers were found.
273 @retval EFI_NOT_FOUND UDF volume identifiers were not found.
274 @retval other Failed to perform disk I/O.
278 FindUdfVolumeIdentifiers (
279 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
280 IN EFI_DISK_IO_PROTOCOL
*DiskIo
285 UINT64 EndDiskOffset
;
286 CDROM_VOLUME_DESCRIPTOR VolDescriptor
;
287 CDROM_VOLUME_DESCRIPTOR TerminatingVolDescriptor
;
289 ZeroMem ((VOID
*)&TerminatingVolDescriptor
, sizeof (CDROM_VOLUME_DESCRIPTOR
));
292 // Start Volume Recognition Sequence
294 EndDiskOffset
= MultU64x32 (BlockIo
->Media
->LastBlock
,
295 BlockIo
->Media
->BlockSize
);
297 for (Offset
= UDF_VRS_START_OFFSET
; Offset
< EndDiskOffset
;
298 Offset
+= UDF_LOGICAL_SECTOR_SIZE
) {
300 // Check if block device has a Volume Structure Descriptor and an Extended
303 Status
= DiskIo
->ReadDisk (
305 BlockIo
->Media
->MediaId
,
307 sizeof (CDROM_VOLUME_DESCRIPTOR
),
308 (VOID
*)&VolDescriptor
310 if (EFI_ERROR (Status
)) {
314 if (CompareMem ((VOID
*)VolDescriptor
.Unknown
.Id
,
315 (VOID
*)UDF_BEA_IDENTIFIER
,
316 sizeof (VolDescriptor
.Unknown
.Id
)) == 0) {
320 if ((CompareMem ((VOID
*)VolDescriptor
.Unknown
.Id
,
322 sizeof (VolDescriptor
.Unknown
.Id
)) != 0) ||
323 (CompareMem ((VOID
*)&VolDescriptor
,
324 (VOID
*)&TerminatingVolDescriptor
,
325 sizeof (CDROM_VOLUME_DESCRIPTOR
)) == 0)) {
326 return EFI_NOT_FOUND
;
331 // Look for "NSR0{2,3}" identifiers in the Extended Area.
333 Offset
+= UDF_LOGICAL_SECTOR_SIZE
;
334 if (Offset
>= EndDiskOffset
) {
335 return EFI_NOT_FOUND
;
338 Status
= DiskIo
->ReadDisk (
340 BlockIo
->Media
->MediaId
,
342 sizeof (CDROM_VOLUME_DESCRIPTOR
),
343 (VOID
*)&VolDescriptor
345 if (EFI_ERROR (Status
)) {
349 if ((CompareMem ((VOID
*)VolDescriptor
.Unknown
.Id
,
350 (VOID
*)UDF_NSR2_IDENTIFIER
,
351 sizeof (VolDescriptor
.Unknown
.Id
)) != 0) &&
352 (CompareMem ((VOID
*)VolDescriptor
.Unknown
.Id
,
353 (VOID
*)UDF_NSR3_IDENTIFIER
,
354 sizeof (VolDescriptor
.Unknown
.Id
)) != 0)) {
355 return EFI_NOT_FOUND
;
359 // Look for "TEA01" identifier in the Extended Area
361 Offset
+= UDF_LOGICAL_SECTOR_SIZE
;
362 if (Offset
>= EndDiskOffset
) {
363 return EFI_NOT_FOUND
;
366 Status
= DiskIo
->ReadDisk (
368 BlockIo
->Media
->MediaId
,
370 sizeof (CDROM_VOLUME_DESCRIPTOR
),
371 (VOID
*)&VolDescriptor
373 if (EFI_ERROR (Status
)) {
377 if (CompareMem ((VOID
*)VolDescriptor
.Unknown
.Id
,
378 (VOID
*)UDF_TEA_IDENTIFIER
,
379 sizeof (VolDescriptor
.Unknown
.Id
)) != 0) {
380 return EFI_NOT_FOUND
;
387 Check if Logical Volume Descriptor is supported by current EDK2 UDF file
388 system implementation.
390 @param[in] LogicalVolDesc Logical Volume Descriptor pointer.
392 @retval TRUE Logical Volume Descriptor is supported.
393 @retval FALSE Logical Volume Descriptor is not supported.
397 IsLogicalVolumeDescriptorSupported (
398 UDF_LOGICAL_VOLUME_DESCRIPTOR
*LogicalVolDesc
402 // Check for a valid UDF revision range
404 switch (LogicalVolDesc
->DomainIdentifier
.Suffix
.Domain
.UdfRevision
) {
417 // Check for a single Partition Map
419 if (LogicalVolDesc
->NumberOfPartitionMaps
> 1) {
423 // UDF 1.02 revision supports only Type 1 (Physical) partitions, but
424 // let's check it any way.
426 // PartitionMap[0] -> type
427 // PartitionMap[1] -> length (in bytes)
429 if (LogicalVolDesc
->PartitionMaps
[0] != 1 ||
430 LogicalVolDesc
->PartitionMaps
[1] != 6) {
438 Find UDF logical volume location and whether it is supported by current EDK2
439 UDF file system implementation.
441 @param[in] BlockIo BlockIo interface.
442 @param[in] DiskIo DiskIo interface.
443 @param[in] AnchorPoint Anchor volume descriptor pointer.
444 @param[in] LastRecordedBlock Last recorded block in media.
445 @param[out] MainVdsStartBlock Main VDS starting block number.
446 @param[out] MainVdsEndBlock Main VDS ending block number.
448 @retval EFI_SUCCESS UDF logical volume was found.
449 @retval EFI_VOLUME_CORRUPTED UDF file system structures are corrupted.
450 @retval EFI_UNSUPPORTED UDF logical volume is not supported.
451 @retval other Failed to perform disk I/O.
455 FindLogicalVolumeLocation (
456 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
457 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
458 IN UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
*AnchorPoint
,
459 IN EFI_LBA LastRecordedBlock
,
460 OUT UINT64
*MainVdsStartBlock
,
461 OUT UINT64
*MainVdsEndBlock
466 UDF_EXTENT_AD
*ExtentAd
;
468 UINT64 SeqStartBlock
;
469 UINT64 GuardMainVdsStartBlock
;
472 BOOLEAN StopSequence
;
474 UDF_LOGICAL_VOLUME_DESCRIPTOR
*LogicalVolDesc
;
475 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
477 BlockSize
= BlockIo
->Media
->BlockSize
;
478 ExtentAd
= &AnchorPoint
->MainVolumeDescriptorSequenceExtent
;
481 // UDF 2.60, 2.2.3.1 struct MainVolumeDescriptorSequenceExtent
483 // The Main Volume Descriptor Sequence Extent shall have a minimum length of
484 // 16 logical sectors.
486 // Also make sure it does not exceed maximum number of blocks in the disk.
488 SeqBlocksNum
= DivU64x32 ((UINT64
)ExtentAd
->ExtentLength
, BlockSize
);
489 if (SeqBlocksNum
< 16 || (EFI_LBA
)SeqBlocksNum
> LastRecordedBlock
+ 1) {
490 return EFI_VOLUME_CORRUPTED
;
494 // Check for valid Volume Descriptor Sequence starting block number
496 SeqStartBlock
= (UINT64
)ExtentAd
->ExtentLocation
;
497 if (SeqStartBlock
> LastRecordedBlock
||
498 SeqStartBlock
+ SeqBlocksNum
- 1 > LastRecordedBlock
) {
499 return EFI_VOLUME_CORRUPTED
;
502 GuardMainVdsStartBlock
= SeqStartBlock
;
505 // Allocate buffer for reading disk blocks
507 Buffer
= AllocateZeroPool ((UINTN
)BlockSize
);
508 if (Buffer
== NULL
) {
509 return EFI_OUT_OF_RESOURCES
;
512 SeqEndBlock
= SeqStartBlock
+ SeqBlocksNum
;
513 StopSequence
= FALSE
;
515 Status
= EFI_VOLUME_CORRUPTED
;
517 // Start Main Volume Descriptor Sequence
519 for (; SeqStartBlock
< SeqEndBlock
&& !StopSequence
; SeqStartBlock
++) {
523 Status
= BlockIo
->ReadBlocks (
525 BlockIo
->Media
->MediaId
,
530 if (EFI_ERROR (Status
)) {
534 DescriptorTag
= Buffer
;
537 // ECMA 167, 8.4.1 Contents of a Volume Descriptor Sequence
539 // - A Volume Descriptor Sequence shall contain one or more Primary Volume
541 // - A Volume Descriptor Sequence shall contain zero or more Implementation
542 // Use Volume Descriptors.
543 // - A Volume Descriptor Sequence shall contain zero or more Partition
545 // - A Volume Descriptor Sequence shall contain zero or more Logical Volume
547 // - A Volume Descriptor Sequence shall contain zero or more Unallocated
548 // Space Descriptors.
550 switch (DescriptorTag
->TagIdentifier
) {
551 case UdfPrimaryVolumeDescriptor
:
552 case UdfImplemenationUseVolumeDescriptor
:
553 case UdfPartitionDescriptor
:
554 case UdfUnallocatedSpaceDescriptor
:
557 case UdfLogicalVolumeDescriptor
:
558 LogicalVolDesc
= Buffer
;
561 // Check for existence of a single LVD and whether it is supported by
562 // current EDK2 UDF file system implementation.
564 if (++LvdsCount
> 1 ||
565 !IsLogicalVolumeDescriptorSupported (LogicalVolDesc
)) {
566 Status
= EFI_UNSUPPORTED
;
572 case UdfTerminatingDescriptor
:
574 // Stop the sequence when we find a Terminating Descriptor
575 // (aka Unallocated Sector), se we don't have to walk all the unallocated
576 // area unnecessarily.
583 // An invalid Volume Descriptor has been found in the sequece. Volume is
586 Status
= EFI_VOLUME_CORRUPTED
;
592 // Check if LVD was found
594 if (!EFI_ERROR (Status
) && LvdsCount
== 1) {
595 *MainVdsStartBlock
= GuardMainVdsStartBlock
;
597 // We do not need to read either LVD or PD descriptors to know the last
598 // valid block in the found UDF file system. It's already
599 // LastRecordedBlock.
601 *MainVdsEndBlock
= LastRecordedBlock
;
603 Status
= EFI_SUCCESS
;
608 // Free block read buffer
616 Find a supported UDF file system in block device.
618 @attention This is boundary function that may receive untrusted input.
619 @attention The input is from Partition.
621 The CD/DVD media is the external input, so this routine will do basic
622 validation for the media.
624 @param[in] BlockIo BlockIo interface.
625 @param[in] DiskIo DiskIo interface.
626 @param[out] StartingLBA UDF file system starting LBA.
627 @param[out] EndingLBA UDF file system starting LBA.
629 @retval EFI_SUCCESS UDF file system was found.
630 @retval other UDF file system was not found.
635 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
636 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
637 OUT EFI_LBA
*StartingLBA
,
638 OUT EFI_LBA
*EndingLBA
642 UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER AnchorPoint
;
643 EFI_LBA LastRecordedBlock
;
646 // Find UDF volume identifiers
648 Status
= FindUdfVolumeIdentifiers (BlockIo
, DiskIo
);
649 if (EFI_ERROR (Status
)) {
654 // Find Anchor Volume Descriptor Pointer
656 Status
= FindAnchorVolumeDescriptorPointer (
662 if (EFI_ERROR (Status
)) {
667 // Find Logical Volume location
669 Status
= FindLogicalVolumeLocation (
674 (UINT64
*)StartingLBA
,
682 Install child handles if the Handle supports UDF/ECMA-167 volume format.
684 @param[in] This Calling context.
685 @param[in] Handle Parent Handle.
686 @param[in] DiskIo Parent DiskIo interface.
687 @param[in] DiskIo2 Parent DiskIo2 interface.
688 @param[in] BlockIo Parent BlockIo interface.
689 @param[in] BlockIo2 Parent BlockIo2 interface.
690 @param[in] DevicePath Parent Device Path
693 @retval EFI_SUCCESS Child handle(s) was added.
694 @retval EFI_MEDIA_CHANGED Media changed Detected.
695 @retval other no child handle was added.
699 PartitionInstallUdfChildHandles (
700 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
701 IN EFI_HANDLE Handle
,
702 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
703 IN EFI_DISK_IO2_PROTOCOL
*DiskIo2
,
704 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
705 IN EFI_BLOCK_IO2_PROTOCOL
*BlockIo2
,
706 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
709 UINT32 RemainderByMediaBlockSize
;
711 EFI_BLOCK_IO_MEDIA
*Media
;
712 EFI_PARTITION_INFO_PROTOCOL PartitionInfo
;
715 BOOLEAN ChildCreated
;
717 Media
= BlockIo
->Media
;
718 ChildCreated
= FALSE
;
721 // Check if UDF logical block size is multiple of underlying device block size
724 UDF_LOGICAL_SECTOR_SIZE
, // Dividend
725 Media
->BlockSize
, // Divisor
726 &RemainderByMediaBlockSize
// Remainder
728 if (RemainderByMediaBlockSize
!= 0) {
729 return EFI_NOT_FOUND
;
733 // Detect El Torito feature first.
734 // And always continue to search for UDF.
736 Status
= PartitionInstallElToritoChildHandles (
745 if (!EFI_ERROR (Status
)) {
746 DEBUG ((DEBUG_INFO
, "PartitionDxe: El Torito standard found on handle 0x%p.\n", Handle
));
751 // Search for an UDF file system on block device
753 Status
= FindUdfFileSystem (BlockIo
, DiskIo
, &StartingLBA
, &EndingLBA
);
754 if (EFI_ERROR (Status
)) {
755 return (ChildCreated
? EFI_SUCCESS
: EFI_NOT_FOUND
);
759 // Create Partition Info protocol for UDF file system
761 ZeroMem (&PartitionInfo
, sizeof (EFI_PARTITION_INFO_PROTOCOL
));
762 PartitionInfo
.Revision
= EFI_PARTITION_INFO_PROTOCOL_REVISION
;
763 PartitionInfo
.Type
= PARTITION_TYPE_OTHER
;
766 // Install partition child handle for UDF file system
768 Status
= PartitionInstallChildHandle (
776 (EFI_DEVICE_PATH_PROTOCOL
*)&gUdfDevicePath
,
783 if (EFI_ERROR (Status
)) {
784 return (ChildCreated
? EFI_SUCCESS
: Status
);