2 Scan for an UDF file system on a formatted media.
4 Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
6 This program and the accompanying materials are licensed and made available
7 under the terms and conditions of the BSD License which accompanies this
8 distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
12 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "Partition.h"
18 // C5BD4D42-1A76-4996-8956-73CDA326CD0A
20 #define EFI_UDF_DEVICE_PATH_GUID \
21 { 0xC5BD4D42, 0x1A76, 0x4996, \
22 { 0x89, 0x56, 0x73, 0xCD, 0xA3, 0x26, 0xCD, 0x0A } \
26 VENDOR_DEVICE_PATH DevicePath
;
27 EFI_DEVICE_PATH_PROTOCOL End
;
31 // Vendor-Defined Device Path GUID for UDF file system
33 EFI_GUID gUdfDevPathGuid
= EFI_UDF_DEVICE_PATH_GUID
;
36 // Vendor-Defined Media Device Path for UDF file system
38 UDF_DEVICE_PATH gUdfDevicePath
= {
39 { { MEDIA_DEVICE_PATH
, MEDIA_VENDOR_DP
,
40 { sizeof (VENDOR_DEVICE_PATH
), 0 } },
41 EFI_UDF_DEVICE_PATH_GUID
43 { END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
,
44 { sizeof (EFI_DEVICE_PATH_PROTOCOL
), 0 }
49 Find the anchor volume descriptor pointer.
51 @param[in] BlockIo BlockIo interface.
52 @param[in] DiskIo DiskIo interface.
53 @param[out] AnchorPoint Anchor volume descriptor pointer.
55 @retval EFI_SUCCESS Anchor volume descriptor pointer found.
56 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
57 @retval other Anchor volume descriptor pointer not found.
61 FindAnchorVolumeDescriptorPointer (
62 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
63 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
64 OUT UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
*AnchorPoint
70 EFI_LBA DescriptorLBAs
[4];
72 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
74 BlockSize
= BlockIo
->Media
->BlockSize
;
75 EndLBA
= BlockIo
->Media
->LastBlock
;
76 DescriptorLBAs
[0] = 256;
77 DescriptorLBAs
[1] = EndLBA
- 256;
78 DescriptorLBAs
[2] = EndLBA
;
79 DescriptorLBAs
[3] = 512;
81 for (Index
= 0; Index
< ARRAY_SIZE (DescriptorLBAs
); Index
++) {
82 Status
= DiskIo
->ReadDisk (
84 BlockIo
->Media
->MediaId
,
85 MultU64x32 (DescriptorLBAs
[Index
], BlockSize
),
86 sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
),
89 if (EFI_ERROR (Status
)) {
93 DescriptorTag
= &AnchorPoint
->DescriptorTag
;
96 // Check if read LBA has a valid AVDP descriptor.
98 if (DescriptorTag
->TagIdentifier
== UdfAnchorVolumeDescriptorPointer
) {
105 return EFI_VOLUME_CORRUPTED
;
109 Find UDF volume identifiers in a Volume Recognition Sequence.
111 @param[in] BlockIo BlockIo interface.
112 @param[in] DiskIo DiskIo interface.
114 @retval EFI_SUCCESS UDF volume identifiers were found.
115 @retval EFI_NOT_FOUND UDF volume identifiers were not found.
116 @retval other Failed to perform disk I/O.
120 FindUdfVolumeIdentifiers (
121 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
122 IN EFI_DISK_IO_PROTOCOL
*DiskIo
127 UINT64 EndDiskOffset
;
128 CDROM_VOLUME_DESCRIPTOR VolDescriptor
;
129 CDROM_VOLUME_DESCRIPTOR TerminatingVolDescriptor
;
131 ZeroMem ((VOID
*)&TerminatingVolDescriptor
, sizeof (CDROM_VOLUME_DESCRIPTOR
));
134 // Start Volume Recognition Sequence
136 EndDiskOffset
= MultU64x32 (BlockIo
->Media
->LastBlock
,
137 BlockIo
->Media
->BlockSize
);
139 for (Offset
= UDF_VRS_START_OFFSET
; Offset
< EndDiskOffset
;
140 Offset
+= UDF_LOGICAL_SECTOR_SIZE
) {
142 // Check if block device has a Volume Structure Descriptor and an Extended
145 Status
= DiskIo
->ReadDisk (
147 BlockIo
->Media
->MediaId
,
149 sizeof (CDROM_VOLUME_DESCRIPTOR
),
150 (VOID
*)&VolDescriptor
152 if (EFI_ERROR (Status
)) {
156 if (CompareMem ((VOID
*)VolDescriptor
.Unknown
.Id
,
157 (VOID
*)UDF_BEA_IDENTIFIER
,
158 sizeof (VolDescriptor
.Unknown
.Id
)) == 0) {
162 if ((CompareMem ((VOID
*)VolDescriptor
.Unknown
.Id
,
164 sizeof (VolDescriptor
.Unknown
.Id
)) != 0) ||
165 (CompareMem ((VOID
*)&VolDescriptor
,
166 (VOID
*)&TerminatingVolDescriptor
,
167 sizeof (CDROM_VOLUME_DESCRIPTOR
)) == 0)) {
168 return EFI_NOT_FOUND
;
173 // Look for "NSR0{2,3}" identifiers in the Extended Area.
175 Offset
+= UDF_LOGICAL_SECTOR_SIZE
;
176 if (Offset
>= EndDiskOffset
) {
177 return EFI_NOT_FOUND
;
180 Status
= DiskIo
->ReadDisk (
182 BlockIo
->Media
->MediaId
,
184 sizeof (CDROM_VOLUME_DESCRIPTOR
),
185 (VOID
*)&VolDescriptor
187 if (EFI_ERROR (Status
)) {
191 if ((CompareMem ((VOID
*)VolDescriptor
.Unknown
.Id
,
192 (VOID
*)UDF_NSR2_IDENTIFIER
,
193 sizeof (VolDescriptor
.Unknown
.Id
)) != 0) &&
194 (CompareMem ((VOID
*)VolDescriptor
.Unknown
.Id
,
195 (VOID
*)UDF_NSR3_IDENTIFIER
,
196 sizeof (VolDescriptor
.Unknown
.Id
)) != 0)) {
197 return EFI_NOT_FOUND
;
201 // Look for "TEA01" identifier in the Extended Area
203 Offset
+= UDF_LOGICAL_SECTOR_SIZE
;
204 if (Offset
>= EndDiskOffset
) {
205 return EFI_NOT_FOUND
;
208 Status
= DiskIo
->ReadDisk (
210 BlockIo
->Media
->MediaId
,
212 sizeof (CDROM_VOLUME_DESCRIPTOR
),
213 (VOID
*)&VolDescriptor
215 if (EFI_ERROR (Status
)) {
219 if (CompareMem ((VOID
*)VolDescriptor
.Unknown
.Id
,
220 (VOID
*)UDF_TEA_IDENTIFIER
,
221 sizeof (VolDescriptor
.Unknown
.Id
)) != 0) {
222 return EFI_NOT_FOUND
;
229 Check if Logical Volume Descriptor is supported by current EDK2 UDF file
230 system implementation.
232 @param[in] LogicalVolDesc Logical Volume Descriptor pointer.
234 @retval TRUE Logical Volume Descriptor is supported.
235 @retval FALSE Logical Volume Descriptor is not supported.
239 IsLogicalVolumeDescriptorSupported (
240 UDF_LOGICAL_VOLUME_DESCRIPTOR
*LogicalVolDesc
244 // Check for a valid UDF revision range
246 switch (LogicalVolDesc
->DomainIdentifier
.Suffix
.Domain
.UdfRevision
) {
259 // Check for a single Partition Map
261 if (LogicalVolDesc
->NumberOfPartitionMaps
> 1) {
265 // UDF 1.02 revision supports only Type 1 (Physical) partitions, but
266 // let's check it any way.
268 // PartitionMap[0] -> type
269 // PartitionMap[1] -> length (in bytes)
271 if (LogicalVolDesc
->PartitionMaps
[0] != 1 ||
272 LogicalVolDesc
->PartitionMaps
[1] != 6) {
280 Find UDF logical volume location and whether it is supported by current EDK2
281 UDF file system implementation.
283 @param[in] BlockIo BlockIo interface.
284 @param[in] DiskIo DiskIo interface.
285 @param[in] AnchorPoint Anchor volume descriptor pointer.
286 @param[out] MainVdsStartBlock Main VDS starting block number.
287 @param[out] MainVdsEndBlock Main VDS ending block number.
289 @retval EFI_SUCCESS UDF logical volume was found.
290 @retval EFI_VOLUME_CORRUPTED UDF file system structures are corrupted.
291 @retval EFI_UNSUPPORTED UDF logical volume is not supported.
292 @retval other Failed to perform disk I/O.
296 FindLogicalVolumeLocation (
297 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
298 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
299 IN UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
*AnchorPoint
,
300 OUT UINT64
*MainVdsStartBlock
,
301 OUT UINT64
*MainVdsEndBlock
307 UDF_EXTENT_AD
*ExtentAd
;
309 UINT64 SeqStartBlock
;
310 UINT64 GuardMainVdsStartBlock
;
313 BOOLEAN StopSequence
;
315 UDF_LOGICAL_VOLUME_DESCRIPTOR
*LogicalVolDesc
;
316 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
318 BlockSize
= BlockIo
->Media
->BlockSize
;
319 LastBlock
= BlockIo
->Media
->LastBlock
;
320 ExtentAd
= &AnchorPoint
->MainVolumeDescriptorSequenceExtent
;
323 // UDF 2.60, 2.2.3.1 struct MainVolumeDescriptorSequenceExtent
325 // The Main Volume Descriptor Sequence Extent shall have a minimum length of
326 // 16 logical sectors.
328 // Also make sure it does not exceed maximum number of blocks in the disk.
330 SeqBlocksNum
= DivU64x32 ((UINT64
)ExtentAd
->ExtentLength
, BlockSize
);
331 if (SeqBlocksNum
< 16 || (EFI_LBA
)SeqBlocksNum
> LastBlock
+ 1) {
332 return EFI_VOLUME_CORRUPTED
;
336 // Check for valid Volume Descriptor Sequence starting block number
338 SeqStartBlock
= (UINT64
)ExtentAd
->ExtentLocation
;
339 if (SeqStartBlock
> LastBlock
||
340 SeqStartBlock
+ SeqBlocksNum
- 1 > LastBlock
) {
341 return EFI_VOLUME_CORRUPTED
;
344 GuardMainVdsStartBlock
= SeqStartBlock
;
347 // Allocate buffer for reading disk blocks
349 Buffer
= AllocateZeroPool ((UINTN
)BlockSize
);
350 if (Buffer
== NULL
) {
351 return EFI_OUT_OF_RESOURCES
;
354 SeqEndBlock
= SeqStartBlock
+ SeqBlocksNum
;
355 StopSequence
= FALSE
;
357 Status
= EFI_VOLUME_CORRUPTED
;
359 // Start Main Volume Descriptor Sequence
361 for (; SeqStartBlock
< SeqEndBlock
&& !StopSequence
; SeqStartBlock
++) {
365 Status
= BlockIo
->ReadBlocks (
367 BlockIo
->Media
->MediaId
,
372 if (EFI_ERROR (Status
)) {
376 DescriptorTag
= Buffer
;
379 // ECMA 167, 8.4.1 Contents of a Volume Descriptor Sequence
381 // - A Volume Descriptor Sequence shall contain one or more Primary Volume
383 // - A Volume Descriptor Sequence shall contain zero or more Implementation
384 // Use Volume Descriptors.
385 // - A Volume Descriptor Sequence shall contain zero or more Partition
387 // - A Volume Descriptor Sequence shall contain zero or more Logical Volume
389 // - A Volume Descriptor Sequence shall contain zero or more Unallocated
390 // Space Descriptors.
392 switch (DescriptorTag
->TagIdentifier
) {
393 case UdfPrimaryVolumeDescriptor
:
394 case UdfImplemenationUseVolumeDescriptor
:
395 case UdfPartitionDescriptor
:
396 case UdfUnallocatedSpaceDescriptor
:
399 case UdfLogicalVolumeDescriptor
:
400 LogicalVolDesc
= Buffer
;
403 // Check for existence of a single LVD and whether it is supported by
404 // current EDK2 UDF file system implementation.
406 if (++LvdsCount
> 1 ||
407 !IsLogicalVolumeDescriptorSupported (LogicalVolDesc
)) {
408 Status
= EFI_UNSUPPORTED
;
414 case UdfTerminatingDescriptor
:
416 // Stop the sequence when we find a Terminating Descriptor
417 // (aka Unallocated Sector), se we don't have to walk all the unallocated
418 // area unnecessarily.
425 // An invalid Volume Descriptor has been found in the sequece. Volume is
428 Status
= EFI_VOLUME_CORRUPTED
;
434 // Check if LVD was found
436 if (!EFI_ERROR (Status
) && LvdsCount
== 1) {
437 *MainVdsStartBlock
= GuardMainVdsStartBlock
;
439 // We do not need to read either LVD or PD descriptors to know the last
440 // valid block in the found UDF file system. It's already LastBlock.
442 *MainVdsEndBlock
= LastBlock
;
444 Status
= EFI_SUCCESS
;
449 // Free block read buffer
457 Find a supported UDF file system in block device.
459 @param[in] BlockIo BlockIo interface.
460 @param[in] DiskIo DiskIo interface.
461 @param[out] StartingLBA UDF file system starting LBA.
462 @param[out] EndingLBA UDF file system starting LBA.
464 @retval EFI_SUCCESS UDF file system was found.
465 @retval other UDF file system was not found.
470 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
471 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
472 OUT EFI_LBA
*StartingLBA
,
473 OUT EFI_LBA
*EndingLBA
477 UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER AnchorPoint
;
480 // Find UDF volume identifiers
482 Status
= FindUdfVolumeIdentifiers (BlockIo
, DiskIo
);
483 if (EFI_ERROR (Status
)) {
488 // Find Anchor Volume Descriptor Pointer
490 Status
= FindAnchorVolumeDescriptorPointer (BlockIo
, DiskIo
, &AnchorPoint
);
491 if (EFI_ERROR (Status
)) {
496 // Find Logical Volume location
498 Status
= FindLogicalVolumeLocation (
502 (UINT64
*)StartingLBA
,
510 Install child handles if the Handle supports UDF/ECMA-167 volume format.
512 @param[in] This Calling context.
513 @param[in] Handle Parent Handle.
514 @param[in] DiskIo Parent DiskIo interface.
515 @param[in] DiskIo2 Parent DiskIo2 interface.
516 @param[in] BlockIo Parent BlockIo interface.
517 @param[in] BlockIo2 Parent BlockIo2 interface.
518 @param[in] DevicePath Parent Device Path
521 @retval EFI_SUCCESS Child handle(s) was added.
522 @retval EFI_MEDIA_CHANGED Media changed Detected.
523 @retval other no child handle was added.
527 PartitionInstallUdfChildHandles (
528 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
529 IN EFI_HANDLE Handle
,
530 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
531 IN EFI_DISK_IO2_PROTOCOL
*DiskIo2
,
532 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
533 IN EFI_BLOCK_IO2_PROTOCOL
*BlockIo2
,
534 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
537 UINT32 RemainderByMediaBlockSize
;
539 EFI_BLOCK_IO_MEDIA
*Media
;
540 EFI_PARTITION_INFO_PROTOCOL PartitionInfo
;
544 Media
= BlockIo
->Media
;
547 // Check if UDF logical block size is multiple of underlying device block size
550 UDF_LOGICAL_SECTOR_SIZE
, // Dividend
551 Media
->BlockSize
, // Divisor
552 &RemainderByMediaBlockSize
// Remainder
554 if (RemainderByMediaBlockSize
!= 0) {
555 return EFI_NOT_FOUND
;
559 // Search for an UDF file system on block device
561 Status
= FindUdfFileSystem (BlockIo
, DiskIo
, &StartingLBA
, &EndingLBA
);
562 if (EFI_ERROR (Status
)) {
563 return EFI_NOT_FOUND
;
567 // Create Partition Info protocol for UDF file system
569 ZeroMem (&PartitionInfo
, sizeof (EFI_PARTITION_INFO_PROTOCOL
));
570 PartitionInfo
.Revision
= EFI_PARTITION_INFO_PROTOCOL_REVISION
;
571 PartitionInfo
.Type
= PARTITION_TYPE_OTHER
;
574 // Install partition child handle for UDF file system
576 Status
= PartitionInstallChildHandle (
584 (EFI_DEVICE_PATH_PROTOCOL
*)&gUdfDevicePath
,