2 Scan for an UDF file system on a formatted media.
4 Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
5 Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
7 This program and the accompanying materials are licensed and made available
8 under the terms and conditions of the BSD License which accompanies this
9 distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
13 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "Partition.h"
18 #define MAX_CORRECTION_BLOCKS_NUM 512u
21 // C5BD4D42-1A76-4996-8956-73CDA326CD0A
23 #define EFI_UDF_DEVICE_PATH_GUID \
24 { 0xC5BD4D42, 0x1A76, 0x4996, \
25 { 0x89, 0x56, 0x73, 0xCD, 0xA3, 0x26, 0xCD, 0x0A } \
29 VENDOR_DEVICE_PATH DevicePath
;
30 EFI_DEVICE_PATH_PROTOCOL End
;
34 // Vendor-Defined Device Path GUID for UDF file system
36 EFI_GUID gUdfDevPathGuid
= EFI_UDF_DEVICE_PATH_GUID
;
39 // Vendor-Defined Media Device Path for UDF file system
41 UDF_DEVICE_PATH gUdfDevicePath
= {
42 { { MEDIA_DEVICE_PATH
, MEDIA_VENDOR_DP
,
43 { sizeof (VENDOR_DEVICE_PATH
), 0 } },
44 EFI_UDF_DEVICE_PATH_GUID
46 { END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
,
47 { sizeof (EFI_DEVICE_PATH_PROTOCOL
), 0 }
52 Find the anchor volume descriptor pointer.
54 @param[in] BlockIo BlockIo interface.
55 @param[in] DiskIo DiskIo interface.
56 @param[out] AnchorPoint Anchor volume descriptor pointer.
57 @param[out] LastRecordedBlock Last recorded block.
59 @retval EFI_SUCCESS Anchor volume descriptor pointer found.
60 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
61 @retval other Anchor volume descriptor pointer not found.
65 FindAnchorVolumeDescriptorPointer (
66 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
67 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
68 OUT UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
*AnchorPoint
,
69 OUT EFI_LBA
*LastRecordedBlock
75 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
78 UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
*AnchorPoints
;
80 UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
*AnchorPointPtr
;
81 EFI_LBA LastAvdpBlockNum
;
84 // UDF 2.60, 2.2.3 Anchor Volume Descriptor Pointer
86 // An Anchor Volume Descriptor Pointer structure shall be recorded in at
87 // least 2 of the following 3 locations on the media: Logical Sector 256,
88 // N - 256 or N, where N is the last *addressable* sector of a volume.
90 // To figure out what logical sector N is, the SCSI commands READ CAPACITY and
91 // READ TRACK INFORMATION are used, however many drives or medias report their
92 // "last recorded block" wrongly. Although, READ CAPACITY returns the last
93 // readable data block but there might be unwritten blocks, which are located
94 // outside any track and therefore AVDP will not be found at block N.
96 // That said, we define a magic number of 512 blocks to be used as correction
97 // when attempting to find AVDP and define last block number.
99 BlockSize
= BlockIo
->Media
->BlockSize
;
100 EndLBA
= BlockIo
->Media
->LastBlock
;
101 *LastRecordedBlock
= EndLBA
;
105 // Find AVDP at block 256
107 Status
= DiskIo
->ReadDisk (
109 BlockIo
->Media
->MediaId
,
110 MultU64x32 (256, BlockSize
),
111 sizeof (*AnchorPoint
),
114 if (EFI_ERROR (Status
)) {
118 DescriptorTag
= &AnchorPoint
->DescriptorTag
;
121 // Check if read block is a valid AVDP descriptor
123 if (DescriptorTag
->TagIdentifier
== UdfAnchorVolumeDescriptorPointer
) {
124 DEBUG ((DEBUG_INFO
, "%a: found AVDP at block %d\n", __FUNCTION__
, 256));
129 // Find AVDP at block N - 256
131 Status
= DiskIo
->ReadDisk (
133 BlockIo
->Media
->MediaId
,
134 MultU64x32 ((UINT64
)EndLBA
- 256, BlockSize
),
135 sizeof (*AnchorPoint
),
138 if (EFI_ERROR (Status
)) {
143 // Check if read block is a valid AVDP descriptor
145 if (DescriptorTag
->TagIdentifier
== UdfAnchorVolumeDescriptorPointer
&&
147 DEBUG ((DEBUG_INFO
, "%a: found AVDP at block %Ld\n", __FUNCTION__
,
153 // Check if at least one AVDP was found in previous locations
155 if (AvdpsCount
== 0) {
156 return EFI_VOLUME_CORRUPTED
;
160 // Find AVDP at block N
162 Status
= DiskIo
->ReadDisk (
164 BlockIo
->Media
->MediaId
,
165 MultU64x32 ((UINT64
)EndLBA
, BlockSize
),
166 sizeof (*AnchorPoint
),
169 if (EFI_ERROR (Status
)) {
174 // Check if read block is a valid AVDP descriptor
176 if (DescriptorTag
->TagIdentifier
== UdfAnchorVolumeDescriptorPointer
) {
181 // No AVDP found at block N. Possibly drive/media returned bad last recorded
182 // block, or it is part of unwritten data blocks and outside any track.
184 // Search backwards for an AVDP from block N-1 through
185 // N-MAX_CORRECTION_BLOCKS_NUM. If any AVDP is found, then correct last block
186 // number for the new UDF partition child handle.
188 Size
= MAX_CORRECTION_BLOCKS_NUM
* BlockSize
;
190 AnchorPoints
= AllocateZeroPool (Size
);
191 if (AnchorPoints
== NULL
) {
192 return EFI_OUT_OF_RESOURCES
;
196 // Read consecutive MAX_CORRECTION_BLOCKS_NUM disk blocks
198 Status
= DiskIo
->ReadDisk (
200 BlockIo
->Media
->MediaId
,
201 MultU64x32 ((UINT64
)EndLBA
- MAX_CORRECTION_BLOCKS_NUM
, BlockSize
),
205 if (EFI_ERROR (Status
)) {
209 Status
= EFI_VOLUME_CORRUPTED
;
212 // Search for AVDP from blocks N-1 through N-MAX_CORRECTION_BLOCKS_NUM
214 for (Index
= MAX_CORRECTION_BLOCKS_NUM
- 2; Index
>= 0; Index
--) {
215 AnchorPointPtr
= (VOID
*)((UINTN
)AnchorPoints
+ Index
* BlockSize
);
217 DescriptorTag
= &AnchorPointPtr
->DescriptorTag
;
220 // Check if read block is a valid AVDP descriptor
222 if (DescriptorTag
->TagIdentifier
== UdfAnchorVolumeDescriptorPointer
) {
224 // Calculate last recorded block number
226 LastAvdpBlockNum
= EndLBA
- (MAX_CORRECTION_BLOCKS_NUM
- Index
);
227 DEBUG ((DEBUG_WARN
, "%a: found AVDP at block %Ld\n", __FUNCTION__
,
229 DEBUG ((DEBUG_WARN
, "%a: correcting last block from %Ld to %Ld\n",
230 __FUNCTION__
, EndLBA
, LastAvdpBlockNum
));
232 // Save read AVDP from last block
234 CopyMem (AnchorPoint
, AnchorPointPtr
, sizeof (*AnchorPointPtr
));
236 // Set last recorded block number
238 *LastRecordedBlock
= LastAvdpBlockNum
;
239 Status
= EFI_SUCCESS
;
245 FreePool (AnchorPoints
);
250 Find UDF volume identifiers in a Volume Recognition Sequence.
252 @param[in] BlockIo BlockIo interface.
253 @param[in] DiskIo DiskIo interface.
255 @retval EFI_SUCCESS UDF volume identifiers were found.
256 @retval EFI_NOT_FOUND UDF volume identifiers were not found.
257 @retval other Failed to perform disk I/O.
261 FindUdfVolumeIdentifiers (
262 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
263 IN EFI_DISK_IO_PROTOCOL
*DiskIo
268 UINT64 EndDiskOffset
;
269 CDROM_VOLUME_DESCRIPTOR VolDescriptor
;
270 CDROM_VOLUME_DESCRIPTOR TerminatingVolDescriptor
;
272 ZeroMem ((VOID
*)&TerminatingVolDescriptor
, sizeof (CDROM_VOLUME_DESCRIPTOR
));
275 // Start Volume Recognition Sequence
277 EndDiskOffset
= MultU64x32 (BlockIo
->Media
->LastBlock
,
278 BlockIo
->Media
->BlockSize
);
280 for (Offset
= UDF_VRS_START_OFFSET
; Offset
< EndDiskOffset
;
281 Offset
+= UDF_LOGICAL_SECTOR_SIZE
) {
283 // Check if block device has a Volume Structure Descriptor and an Extended
286 Status
= DiskIo
->ReadDisk (
288 BlockIo
->Media
->MediaId
,
290 sizeof (CDROM_VOLUME_DESCRIPTOR
),
291 (VOID
*)&VolDescriptor
293 if (EFI_ERROR (Status
)) {
297 if (CompareMem ((VOID
*)VolDescriptor
.Unknown
.Id
,
298 (VOID
*)UDF_BEA_IDENTIFIER
,
299 sizeof (VolDescriptor
.Unknown
.Id
)) == 0) {
303 if ((CompareMem ((VOID
*)VolDescriptor
.Unknown
.Id
,
305 sizeof (VolDescriptor
.Unknown
.Id
)) != 0) ||
306 (CompareMem ((VOID
*)&VolDescriptor
,
307 (VOID
*)&TerminatingVolDescriptor
,
308 sizeof (CDROM_VOLUME_DESCRIPTOR
)) == 0)) {
309 return EFI_NOT_FOUND
;
314 // Look for "NSR0{2,3}" identifiers in the Extended Area.
316 Offset
+= UDF_LOGICAL_SECTOR_SIZE
;
317 if (Offset
>= EndDiskOffset
) {
318 return EFI_NOT_FOUND
;
321 Status
= DiskIo
->ReadDisk (
323 BlockIo
->Media
->MediaId
,
325 sizeof (CDROM_VOLUME_DESCRIPTOR
),
326 (VOID
*)&VolDescriptor
328 if (EFI_ERROR (Status
)) {
332 if ((CompareMem ((VOID
*)VolDescriptor
.Unknown
.Id
,
333 (VOID
*)UDF_NSR2_IDENTIFIER
,
334 sizeof (VolDescriptor
.Unknown
.Id
)) != 0) &&
335 (CompareMem ((VOID
*)VolDescriptor
.Unknown
.Id
,
336 (VOID
*)UDF_NSR3_IDENTIFIER
,
337 sizeof (VolDescriptor
.Unknown
.Id
)) != 0)) {
338 return EFI_NOT_FOUND
;
342 // Look for "TEA01" identifier in the Extended Area
344 Offset
+= UDF_LOGICAL_SECTOR_SIZE
;
345 if (Offset
>= EndDiskOffset
) {
346 return EFI_NOT_FOUND
;
349 Status
= DiskIo
->ReadDisk (
351 BlockIo
->Media
->MediaId
,
353 sizeof (CDROM_VOLUME_DESCRIPTOR
),
354 (VOID
*)&VolDescriptor
356 if (EFI_ERROR (Status
)) {
360 if (CompareMem ((VOID
*)VolDescriptor
.Unknown
.Id
,
361 (VOID
*)UDF_TEA_IDENTIFIER
,
362 sizeof (VolDescriptor
.Unknown
.Id
)) != 0) {
363 return EFI_NOT_FOUND
;
370 Check if Logical Volume Descriptor is supported by current EDK2 UDF file
371 system implementation.
373 @param[in] LogicalVolDesc Logical Volume Descriptor pointer.
375 @retval TRUE Logical Volume Descriptor is supported.
376 @retval FALSE Logical Volume Descriptor is not supported.
380 IsLogicalVolumeDescriptorSupported (
381 UDF_LOGICAL_VOLUME_DESCRIPTOR
*LogicalVolDesc
385 // Check for a valid UDF revision range
387 switch (LogicalVolDesc
->DomainIdentifier
.Suffix
.Domain
.UdfRevision
) {
400 // Check for a single Partition Map
402 if (LogicalVolDesc
->NumberOfPartitionMaps
> 1) {
406 // UDF 1.02 revision supports only Type 1 (Physical) partitions, but
407 // let's check it any way.
409 // PartitionMap[0] -> type
410 // PartitionMap[1] -> length (in bytes)
412 if (LogicalVolDesc
->PartitionMaps
[0] != 1 ||
413 LogicalVolDesc
->PartitionMaps
[1] != 6) {
421 Find UDF logical volume location and whether it is supported by current EDK2
422 UDF file system implementation.
424 @param[in] BlockIo BlockIo interface.
425 @param[in] DiskIo DiskIo interface.
426 @param[in] AnchorPoint Anchor volume descriptor pointer.
427 @param[in] LastRecordedBlock Last recorded block in media.
428 @param[out] MainVdsStartBlock Main VDS starting block number.
429 @param[out] MainVdsEndBlock Main VDS ending block number.
431 @retval EFI_SUCCESS UDF logical volume was found.
432 @retval EFI_VOLUME_CORRUPTED UDF file system structures are corrupted.
433 @retval EFI_UNSUPPORTED UDF logical volume is not supported.
434 @retval other Failed to perform disk I/O.
438 FindLogicalVolumeLocation (
439 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
440 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
441 IN UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
*AnchorPoint
,
442 IN EFI_LBA LastRecordedBlock
,
443 OUT UINT64
*MainVdsStartBlock
,
444 OUT UINT64
*MainVdsEndBlock
449 UDF_EXTENT_AD
*ExtentAd
;
451 UINT64 SeqStartBlock
;
452 UINT64 GuardMainVdsStartBlock
;
455 BOOLEAN StopSequence
;
457 UDF_LOGICAL_VOLUME_DESCRIPTOR
*LogicalVolDesc
;
458 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
460 BlockSize
= BlockIo
->Media
->BlockSize
;
461 ExtentAd
= &AnchorPoint
->MainVolumeDescriptorSequenceExtent
;
464 // UDF 2.60, 2.2.3.1 struct MainVolumeDescriptorSequenceExtent
466 // The Main Volume Descriptor Sequence Extent shall have a minimum length of
467 // 16 logical sectors.
469 // Also make sure it does not exceed maximum number of blocks in the disk.
471 SeqBlocksNum
= DivU64x32 ((UINT64
)ExtentAd
->ExtentLength
, BlockSize
);
472 if (SeqBlocksNum
< 16 || (EFI_LBA
)SeqBlocksNum
> LastRecordedBlock
+ 1) {
473 return EFI_VOLUME_CORRUPTED
;
477 // Check for valid Volume Descriptor Sequence starting block number
479 SeqStartBlock
= (UINT64
)ExtentAd
->ExtentLocation
;
480 if (SeqStartBlock
> LastRecordedBlock
||
481 SeqStartBlock
+ SeqBlocksNum
- 1 > LastRecordedBlock
) {
482 return EFI_VOLUME_CORRUPTED
;
485 GuardMainVdsStartBlock
= SeqStartBlock
;
488 // Allocate buffer for reading disk blocks
490 Buffer
= AllocateZeroPool ((UINTN
)BlockSize
);
491 if (Buffer
== NULL
) {
492 return EFI_OUT_OF_RESOURCES
;
495 SeqEndBlock
= SeqStartBlock
+ SeqBlocksNum
;
496 StopSequence
= FALSE
;
498 Status
= EFI_VOLUME_CORRUPTED
;
500 // Start Main Volume Descriptor Sequence
502 for (; SeqStartBlock
< SeqEndBlock
&& !StopSequence
; SeqStartBlock
++) {
506 Status
= BlockIo
->ReadBlocks (
508 BlockIo
->Media
->MediaId
,
513 if (EFI_ERROR (Status
)) {
517 DescriptorTag
= Buffer
;
520 // ECMA 167, 8.4.1 Contents of a Volume Descriptor Sequence
522 // - A Volume Descriptor Sequence shall contain one or more Primary Volume
524 // - A Volume Descriptor Sequence shall contain zero or more Implementation
525 // Use Volume Descriptors.
526 // - A Volume Descriptor Sequence shall contain zero or more Partition
528 // - A Volume Descriptor Sequence shall contain zero or more Logical Volume
530 // - A Volume Descriptor Sequence shall contain zero or more Unallocated
531 // Space Descriptors.
533 switch (DescriptorTag
->TagIdentifier
) {
534 case UdfPrimaryVolumeDescriptor
:
535 case UdfImplemenationUseVolumeDescriptor
:
536 case UdfPartitionDescriptor
:
537 case UdfUnallocatedSpaceDescriptor
:
540 case UdfLogicalVolumeDescriptor
:
541 LogicalVolDesc
= Buffer
;
544 // Check for existence of a single LVD and whether it is supported by
545 // current EDK2 UDF file system implementation.
547 if (++LvdsCount
> 1 ||
548 !IsLogicalVolumeDescriptorSupported (LogicalVolDesc
)) {
549 Status
= EFI_UNSUPPORTED
;
555 case UdfTerminatingDescriptor
:
557 // Stop the sequence when we find a Terminating Descriptor
558 // (aka Unallocated Sector), se we don't have to walk all the unallocated
559 // area unnecessarily.
566 // An invalid Volume Descriptor has been found in the sequece. Volume is
569 Status
= EFI_VOLUME_CORRUPTED
;
575 // Check if LVD was found
577 if (!EFI_ERROR (Status
) && LvdsCount
== 1) {
578 *MainVdsStartBlock
= GuardMainVdsStartBlock
;
580 // We do not need to read either LVD or PD descriptors to know the last
581 // valid block in the found UDF file system. It's already
582 // LastRecordedBlock.
584 *MainVdsEndBlock
= LastRecordedBlock
;
586 Status
= EFI_SUCCESS
;
591 // Free block read buffer
599 Find a supported UDF file system in block device.
601 @param[in] BlockIo BlockIo interface.
602 @param[in] DiskIo DiskIo interface.
603 @param[out] StartingLBA UDF file system starting LBA.
604 @param[out] EndingLBA UDF file system starting LBA.
606 @retval EFI_SUCCESS UDF file system was found.
607 @retval other UDF file system was not found.
612 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
613 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
614 OUT EFI_LBA
*StartingLBA
,
615 OUT EFI_LBA
*EndingLBA
619 UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER AnchorPoint
;
620 EFI_LBA LastRecordedBlock
;
623 // Find UDF volume identifiers
625 Status
= FindUdfVolumeIdentifiers (BlockIo
, DiskIo
);
626 if (EFI_ERROR (Status
)) {
631 // Find Anchor Volume Descriptor Pointer
633 Status
= FindAnchorVolumeDescriptorPointer (
639 if (EFI_ERROR (Status
)) {
644 // Find Logical Volume location
646 Status
= FindLogicalVolumeLocation (
651 (UINT64
*)StartingLBA
,
659 Install child handles if the Handle supports UDF/ECMA-167 volume format.
661 @param[in] This Calling context.
662 @param[in] Handle Parent Handle.
663 @param[in] DiskIo Parent DiskIo interface.
664 @param[in] DiskIo2 Parent DiskIo2 interface.
665 @param[in] BlockIo Parent BlockIo interface.
666 @param[in] BlockIo2 Parent BlockIo2 interface.
667 @param[in] DevicePath Parent Device Path
670 @retval EFI_SUCCESS Child handle(s) was added.
671 @retval EFI_MEDIA_CHANGED Media changed Detected.
672 @retval other no child handle was added.
676 PartitionInstallUdfChildHandles (
677 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
678 IN EFI_HANDLE Handle
,
679 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
680 IN EFI_DISK_IO2_PROTOCOL
*DiskIo2
,
681 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
682 IN EFI_BLOCK_IO2_PROTOCOL
*BlockIo2
,
683 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
686 UINT32 RemainderByMediaBlockSize
;
688 EFI_BLOCK_IO_MEDIA
*Media
;
689 EFI_PARTITION_INFO_PROTOCOL PartitionInfo
;
692 BOOLEAN ChildCreated
;
694 Media
= BlockIo
->Media
;
695 ChildCreated
= FALSE
;
698 // Check if UDF logical block size is multiple of underlying device block size
701 UDF_LOGICAL_SECTOR_SIZE
, // Dividend
702 Media
->BlockSize
, // Divisor
703 &RemainderByMediaBlockSize
// Remainder
705 if (RemainderByMediaBlockSize
!= 0) {
706 return EFI_NOT_FOUND
;
710 // Detect El Torito feature first.
711 // And always continue to search for UDF.
713 Status
= PartitionInstallElToritoChildHandles (
722 if (!EFI_ERROR (Status
)) {
723 DEBUG ((DEBUG_INFO
, "PartitionDxe: El Torito standard found on handle 0x%p.\n", Handle
));
728 // Search for an UDF file system on block device
730 Status
= FindUdfFileSystem (BlockIo
, DiskIo
, &StartingLBA
, &EndingLBA
);
731 if (EFI_ERROR (Status
)) {
732 return (ChildCreated
? EFI_SUCCESS
: EFI_NOT_FOUND
);
736 // Create Partition Info protocol for UDF file system
738 ZeroMem (&PartitionInfo
, sizeof (EFI_PARTITION_INFO_PROTOCOL
));
739 PartitionInfo
.Revision
= EFI_PARTITION_INFO_PROTOCOL_REVISION
;
740 PartitionInfo
.Type
= PARTITION_TYPE_OTHER
;
743 // Install partition child handle for UDF file system
745 Status
= PartitionInstallChildHandle (
753 (EFI_DEVICE_PATH_PROTOCOL
*)&gUdfDevicePath
,
760 if (EFI_ERROR (Status
)) {
761 return (ChildCreated
? EFI_SUCCESS
: Status
);