1 /** @file
2   Scan for an UDF file system on a formatted media.
3 
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.
8 
9   FindUdfFileSystem() routine will consume the media properties and do basic
10   validation.
11 
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>
15 
16   SPDX-License-Identifier: BSD-2-Clause-Patent
17 **/
18 
19 #include "Partition.h"
20 
21 #define MAX_CORRECTION_BLOCKS_NUM 512u
22 
23 //
24 // C5BD4D42-1A76-4996-8956-73CDA326CD0A
25 //
26 #define EFI_UDF_DEVICE_PATH_GUID                        \
27   { 0xC5BD4D42, 0x1A76, 0x4996,                         \
28     { 0x89, 0x56, 0x73, 0xCD, 0xA3, 0x26, 0xCD, 0x0A }  \
29   }
30 
31 typedef struct {
32   VENDOR_DEVICE_PATH        DevicePath;
33   EFI_DEVICE_PATH_PROTOCOL  End;
34 } UDF_DEVICE_PATH;
35 
36 //
37 // Vendor-Defined Device Path GUID for UDF file system
38 //
39 EFI_GUID gUdfDevPathGuid = EFI_UDF_DEVICE_PATH_GUID;
40 
41 //
42 // Vendor-Defined Media Device Path for UDF file system
43 //
44 UDF_DEVICE_PATH gUdfDevicePath = {
45   { { MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP,
46       { sizeof (VENDOR_DEVICE_PATH), 0 } },
47     EFI_UDF_DEVICE_PATH_GUID
48   },
49   { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
50     { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
51   }
52 };
53 
54 /**
55   Find the anchor volume descriptor pointer.
56 
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.
61 
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.
65 
66 **/
67 EFI_STATUS
FindAnchorVolumeDescriptorPointer(IN EFI_BLOCK_IO_PROTOCOL * BlockIo,IN EFI_DISK_IO_PROTOCOL * DiskIo,OUT UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER * AnchorPoint,OUT EFI_LBA * LastRecordedBlock)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
73   )
74 {
75   EFI_STATUS                            Status;
76   UINT32                                BlockSize;
77   EFI_LBA                               EndLBA;
78   UDF_DESCRIPTOR_TAG                    *DescriptorTag;
79   UINTN                                 AvdpsCount;
80   UINTN                                 Size;
81   UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER  *AnchorPoints;
82   INTN                                  Index;
83   UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER  *AnchorPointPtr;
84   EFI_LBA                               LastAvdpBlockNum;
85 
86   //
87   // UDF 2.60, 2.2.3 Anchor Volume Descriptor Pointer
88   //
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.
92   //
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.
98   //
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.
101   //
102   BlockSize = BlockIo->Media->BlockSize;
103   EndLBA = BlockIo->Media->LastBlock;
104   *LastRecordedBlock = EndLBA;
105   AvdpsCount = 0;
106 
107   //
108   // Check if the block size of the underlying media can hold the data of an
109   // Anchor Volume Descriptor Pointer
110   //
111   if (BlockSize < sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER)) {
112     DEBUG ((
113       DEBUG_ERROR,
114       "%a: Media block size 0x%x unable to hold an AVDP.\n",
115       __FUNCTION__,
116       BlockSize
117       ));
118     return EFI_UNSUPPORTED;
119   }
120 
121   //
122   // Find AVDP at block 256
123   //
124   Status = DiskIo->ReadDisk (
125     DiskIo,
126     BlockIo->Media->MediaId,
127     MultU64x32 (256, BlockSize),
128     sizeof (*AnchorPoint),
129     AnchorPoint
130     );
131   if (EFI_ERROR (Status)) {
132     return Status;
133   }
134 
135   DescriptorTag = &AnchorPoint->DescriptorTag;
136 
137   //
138   // Check if read block is a valid AVDP descriptor
139   //
140   if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) {
141     DEBUG ((DEBUG_INFO, "%a: found AVDP at block %d\n", __FUNCTION__, 256));
142     AvdpsCount++;
143   }
144 
145   //
146   // Find AVDP at block N - 256
147   //
148   Status = DiskIo->ReadDisk (
149     DiskIo,
150     BlockIo->Media->MediaId,
151     MultU64x32 ((UINT64)EndLBA - 256, BlockSize),
152     sizeof (*AnchorPoint),
153     AnchorPoint
154     );
155   if (EFI_ERROR (Status)) {
156     return Status;
157   }
158 
159   //
160   // Check if read block is a valid AVDP descriptor
161   //
162   if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer &&
163       ++AvdpsCount == 2) {
164     DEBUG ((DEBUG_INFO, "%a: found AVDP at block %Ld\n", __FUNCTION__,
165             EndLBA - 256));
166     return EFI_SUCCESS;
167   }
168 
169   //
170   // Check if at least one AVDP was found in previous locations
171   //
172   if (AvdpsCount == 0) {
173     return EFI_VOLUME_CORRUPTED;
174   }
175 
176   //
177   // Find AVDP at block N
178   //
179   Status = DiskIo->ReadDisk (
180     DiskIo,
181     BlockIo->Media->MediaId,
182     MultU64x32 ((UINT64)EndLBA, BlockSize),
183     sizeof (*AnchorPoint),
184     AnchorPoint
185     );
186   if (EFI_ERROR (Status)) {
187     return Status;
188   }
189 
190   //
191   // Check if read block is a valid AVDP descriptor
192   //
193   if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) {
194     return EFI_SUCCESS;
195   }
196 
197   //
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.
200   //
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.
204   //
205   Size = MAX_CORRECTION_BLOCKS_NUM * BlockSize;
206 
207   AnchorPoints = AllocateZeroPool (Size);
208   if (AnchorPoints == NULL) {
209     return EFI_OUT_OF_RESOURCES;
210   }
211 
212   //
213   // Read consecutive MAX_CORRECTION_BLOCKS_NUM disk blocks
214   //
215   Status = DiskIo->ReadDisk (
216     DiskIo,
217     BlockIo->Media->MediaId,
218     MultU64x32 ((UINT64)EndLBA - MAX_CORRECTION_BLOCKS_NUM, BlockSize),
219     Size,
220     AnchorPoints
221     );
222   if (EFI_ERROR (Status)) {
223     goto Out_Free;
224   }
225 
226   Status = EFI_VOLUME_CORRUPTED;
227 
228   //
229   // Search for AVDP from blocks N-1 through N-MAX_CORRECTION_BLOCKS_NUM
230   //
231   for (Index = MAX_CORRECTION_BLOCKS_NUM - 2; Index >= 0; Index--) {
232     AnchorPointPtr = (VOID *)((UINTN)AnchorPoints + Index * BlockSize);
233 
234     DescriptorTag = &AnchorPointPtr->DescriptorTag;
235 
236     //
237     // Check if read block is a valid AVDP descriptor
238     //
239     if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) {
240       //
241       // Calculate last recorded block number
242       //
243       LastAvdpBlockNum = EndLBA - (MAX_CORRECTION_BLOCKS_NUM - Index);
244       DEBUG ((DEBUG_WARN, "%a: found AVDP at block %Ld\n", __FUNCTION__,
245               LastAvdpBlockNum));
246       DEBUG ((DEBUG_WARN, "%a: correcting last block from %Ld to %Ld\n",
247               __FUNCTION__, EndLBA, LastAvdpBlockNum));
248       //
249       // Save read AVDP from last block
250       //
251       CopyMem (AnchorPoint, AnchorPointPtr, sizeof (*AnchorPointPtr));
252       //
253       // Set last recorded block number
254       //
255       *LastRecordedBlock = LastAvdpBlockNum;
256       Status = EFI_SUCCESS;
257       break;
258     }
259   }
260 
261 Out_Free:
262   FreePool (AnchorPoints);
263   return Status;
264 }
265 
266 /**
267   Find UDF volume identifiers in a Volume Recognition Sequence.
268 
269   @param[in]  BlockIo             BlockIo interface.
270   @param[in]  DiskIo              DiskIo interface.
271 
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.
275 
276 **/
277 EFI_STATUS
FindUdfVolumeIdentifiers(IN EFI_BLOCK_IO_PROTOCOL * BlockIo,IN EFI_DISK_IO_PROTOCOL * DiskIo)278 FindUdfVolumeIdentifiers (
279   IN EFI_BLOCK_IO_PROTOCOL  *BlockIo,
280   IN EFI_DISK_IO_PROTOCOL   *DiskIo
281   )
282 {
283   EFI_STATUS                            Status;
284   UINT64                                Offset;
285   UINT64                                EndDiskOffset;
286   CDROM_VOLUME_DESCRIPTOR               VolDescriptor;
287   CDROM_VOLUME_DESCRIPTOR               TerminatingVolDescriptor;
288 
289   ZeroMem ((VOID *)&TerminatingVolDescriptor, sizeof (CDROM_VOLUME_DESCRIPTOR));
290 
291   //
292   // Start Volume Recognition Sequence
293   //
294   EndDiskOffset = MultU64x32 (BlockIo->Media->LastBlock,
295                               BlockIo->Media->BlockSize);
296 
297   for (Offset = UDF_VRS_START_OFFSET; Offset < EndDiskOffset;
298        Offset += UDF_LOGICAL_SECTOR_SIZE) {
299     //
300     // Check if block device has a Volume Structure Descriptor and an Extended
301     // Area.
302     //
303     Status = DiskIo->ReadDisk (
304       DiskIo,
305       BlockIo->Media->MediaId,
306       Offset,
307       sizeof (CDROM_VOLUME_DESCRIPTOR),
308       (VOID *)&VolDescriptor
309       );
310     if (EFI_ERROR (Status)) {
311       return Status;
312     }
313 
314     if (CompareMem ((VOID *)VolDescriptor.Unknown.Id,
315                     (VOID *)UDF_BEA_IDENTIFIER,
316                     sizeof (VolDescriptor.Unknown.Id)) == 0) {
317       break;
318     }
319 
320     if ((CompareMem ((VOID *)VolDescriptor.Unknown.Id,
321                      (VOID *)CDVOL_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;
327     }
328   }
329 
330   //
331   // Look for "NSR0{2,3}" identifiers in the Extended Area.
332   //
333   Offset += UDF_LOGICAL_SECTOR_SIZE;
334   if (Offset >= EndDiskOffset) {
335     return EFI_NOT_FOUND;
336   }
337 
338   Status = DiskIo->ReadDisk (
339     DiskIo,
340     BlockIo->Media->MediaId,
341     Offset,
342     sizeof (CDROM_VOLUME_DESCRIPTOR),
343     (VOID *)&VolDescriptor
344     );
345   if (EFI_ERROR (Status)) {
346     return Status;
347   }
348 
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;
356   }
357 
358   //
359   // Look for "TEA01" identifier in the Extended Area
360   //
361   Offset += UDF_LOGICAL_SECTOR_SIZE;
362   if (Offset >= EndDiskOffset) {
363     return EFI_NOT_FOUND;
364   }
365 
366   Status = DiskIo->ReadDisk (
367     DiskIo,
368     BlockIo->Media->MediaId,
369     Offset,
370     sizeof (CDROM_VOLUME_DESCRIPTOR),
371     (VOID *)&VolDescriptor
372     );
373   if (EFI_ERROR (Status)) {
374     return Status;
375   }
376 
377   if (CompareMem ((VOID *)VolDescriptor.Unknown.Id,
378                   (VOID *)UDF_TEA_IDENTIFIER,
379                   sizeof (VolDescriptor.Unknown.Id)) != 0) {
380     return EFI_NOT_FOUND;
381   }
382 
383   return EFI_SUCCESS;
384 }
385 
386 /**
387   Check if Logical Volume Descriptor is supported by current EDK2 UDF file
388   system implementation.
389 
390   @param[in]  LogicalVolDesc  Logical Volume Descriptor pointer.
391 
392   @retval TRUE                Logical Volume Descriptor is supported.
393   @retval FALSE               Logical Volume Descriptor is not supported.
394 
395 **/
396 BOOLEAN
IsLogicalVolumeDescriptorSupported(UDF_LOGICAL_VOLUME_DESCRIPTOR * LogicalVolDesc)397 IsLogicalVolumeDescriptorSupported (
398   UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc
399   )
400 {
401   //
402   // Check for a valid UDF revision range
403   //
404   switch (LogicalVolDesc->DomainIdentifier.Suffix.Domain.UdfRevision) {
405   case 0x0102:
406   case 0x0150:
407   case 0x0200:
408   case 0x0201:
409   case 0x0250:
410   case 0x0260:
411     break;
412   default:
413     return FALSE;
414   }
415 
416   //
417   // Check for a single Partition Map
418   //
419   if (LogicalVolDesc->NumberOfPartitionMaps > 1) {
420     return FALSE;
421   }
422   //
423   // UDF 1.02 revision supports only Type 1 (Physical) partitions, but
424   // let's check it any way.
425   //
426   // PartitionMap[0] -> type
427   // PartitionMap[1] -> length (in bytes)
428   //
429   if (LogicalVolDesc->PartitionMaps[0] != 1 ||
430       LogicalVolDesc->PartitionMaps[1] != 6) {
431     return FALSE;
432   }
433 
434   return TRUE;
435 }
436 
437 /**
438   Find UDF logical volume location and whether it is supported by current EDK2
439   UDF file system implementation.
440 
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.
447 
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.
452 
453 **/
454 EFI_STATUS
FindLogicalVolumeLocation(IN EFI_BLOCK_IO_PROTOCOL * BlockIo,IN EFI_DISK_IO_PROTOCOL * DiskIo,IN UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER * AnchorPoint,IN EFI_LBA LastRecordedBlock,OUT UINT64 * MainVdsStartBlock,OUT UINT64 * MainVdsEndBlock)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
462   )
463 {
464   EFI_STATUS                     Status;
465   UINT32                         BlockSize;
466   UDF_EXTENT_AD                  *ExtentAd;
467   UINT64                         SeqBlocksNum;
468   UINT64                         SeqStartBlock;
469   UINT64                         GuardMainVdsStartBlock;
470   VOID                           *Buffer;
471   UINT64                         SeqEndBlock;
472   BOOLEAN                        StopSequence;
473   UINTN                          LvdsCount;
474   UDF_LOGICAL_VOLUME_DESCRIPTOR  *LogicalVolDesc;
475   UDF_DESCRIPTOR_TAG             *DescriptorTag;
476 
477   BlockSize = BlockIo->Media->BlockSize;
478   ExtentAd = &AnchorPoint->MainVolumeDescriptorSequenceExtent;
479 
480   //
481   // UDF 2.60, 2.2.3.1 struct MainVolumeDescriptorSequenceExtent
482   //
483   // The Main Volume Descriptor Sequence Extent shall have a minimum length of
484   // 16 logical sectors.
485   //
486   // Also make sure it does not exceed maximum number of blocks in the disk.
487   //
488   SeqBlocksNum = DivU64x32 ((UINT64)ExtentAd->ExtentLength, BlockSize);
489   if (SeqBlocksNum < 16 || (EFI_LBA)SeqBlocksNum > LastRecordedBlock + 1) {
490     return EFI_VOLUME_CORRUPTED;
491   }
492 
493   //
494   // Check for valid Volume Descriptor Sequence starting block number
495   //
496   SeqStartBlock = (UINT64)ExtentAd->ExtentLocation;
497   if (SeqStartBlock > LastRecordedBlock ||
498       SeqStartBlock + SeqBlocksNum - 1 > LastRecordedBlock) {
499     return EFI_VOLUME_CORRUPTED;
500   }
501 
502   GuardMainVdsStartBlock = SeqStartBlock;
503 
504   //
505   // Allocate buffer for reading disk blocks
506   //
507   Buffer = AllocateZeroPool ((UINTN)BlockSize);
508   if (Buffer == NULL) {
509     return EFI_OUT_OF_RESOURCES;
510   }
511 
512   SeqEndBlock = SeqStartBlock + SeqBlocksNum;
513   StopSequence = FALSE;
514   LvdsCount = 0;
515   Status = EFI_VOLUME_CORRUPTED;
516   //
517   // Start Main Volume Descriptor Sequence
518   //
519   for (; SeqStartBlock < SeqEndBlock && !StopSequence; SeqStartBlock++) {
520     //
521     // Read disk block
522     //
523     Status = BlockIo->ReadBlocks (
524       BlockIo,
525       BlockIo->Media->MediaId,
526       SeqStartBlock,
527       BlockSize,
528       Buffer
529       );
530     if (EFI_ERROR (Status)) {
531       goto Out_Free;
532     }
533 
534     DescriptorTag = Buffer;
535 
536     //
537     // ECMA 167, 8.4.1 Contents of a Volume Descriptor Sequence
538     //
539     // - A Volume Descriptor Sequence shall contain one or more Primary Volume
540     //   Descriptors.
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
544     //   Descriptors.
545     // - A Volume Descriptor Sequence shall contain zero or more Logical Volume
546     //   Descriptors.
547     // - A Volume Descriptor Sequence shall contain zero or more Unallocated
548     //   Space Descriptors.
549     //
550     switch (DescriptorTag->TagIdentifier) {
551     case UdfPrimaryVolumeDescriptor:
552     case UdfImplemenationUseVolumeDescriptor:
553     case UdfPartitionDescriptor:
554     case UdfUnallocatedSpaceDescriptor:
555       break;
556 
557     case UdfLogicalVolumeDescriptor:
558       LogicalVolDesc = Buffer;
559 
560       //
561       // Check for existence of a single LVD and whether it is supported by
562       // current EDK2 UDF file system implementation.
563       //
564       if (++LvdsCount > 1 ||
565           !IsLogicalVolumeDescriptorSupported (LogicalVolDesc)) {
566         Status = EFI_UNSUPPORTED;
567         StopSequence = TRUE;
568       }
569 
570       break;
571 
572     case UdfTerminatingDescriptor:
573       //
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.
577       //
578       StopSequence = TRUE;
579       break;
580 
581     default:
582       //
583       // An invalid Volume Descriptor has been found in the sequece. Volume is
584       // corrupted.
585       //
586       Status = EFI_VOLUME_CORRUPTED;
587       goto Out_Free;
588     }
589   }
590 
591   //
592   // Check if LVD was found
593   //
594   if (!EFI_ERROR (Status) && LvdsCount == 1) {
595     *MainVdsStartBlock = GuardMainVdsStartBlock;
596     //
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.
600     //
601     *MainVdsEndBlock = LastRecordedBlock;
602 
603     Status = EFI_SUCCESS;
604   }
605 
606 Out_Free:
607   //
608   // Free block read buffer
609   //
610   FreePool (Buffer);
611 
612   return Status;
613 }
614 
615 /**
616   Find a supported UDF file system in block device.
617 
618   @attention This is boundary function that may receive untrusted input.
619   @attention The input is from Partition.
620 
621   The CD/DVD media is the external input, so this routine will do basic
622   validation for the media.
623 
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.
628 
629   @retval EFI_SUCCESS             UDF file system was found.
630   @retval other                   UDF file system was not found.
631 
632 **/
633 EFI_STATUS
FindUdfFileSystem(IN EFI_BLOCK_IO_PROTOCOL * BlockIo,IN EFI_DISK_IO_PROTOCOL * DiskIo,OUT EFI_LBA * StartingLBA,OUT EFI_LBA * EndingLBA)634 FindUdfFileSystem (
635   IN EFI_BLOCK_IO_PROTOCOL  *BlockIo,
636   IN EFI_DISK_IO_PROTOCOL   *DiskIo,
637   OUT EFI_LBA               *StartingLBA,
638   OUT EFI_LBA               *EndingLBA
639   )
640 {
641   EFI_STATUS                            Status;
642   UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER  AnchorPoint;
643   EFI_LBA                               LastRecordedBlock;
644 
645   //
646   // Find UDF volume identifiers
647   //
648   Status = FindUdfVolumeIdentifiers (BlockIo, DiskIo);
649   if (EFI_ERROR (Status)) {
650     return Status;
651   }
652 
653   //
654   // Find Anchor Volume Descriptor Pointer
655   //
656   Status = FindAnchorVolumeDescriptorPointer (
657     BlockIo,
658     DiskIo,
659     &AnchorPoint,
660     &LastRecordedBlock
661     );
662   if (EFI_ERROR (Status)) {
663     return Status;
664   }
665 
666   //
667   // Find Logical Volume location
668   //
669   Status = FindLogicalVolumeLocation (
670     BlockIo,
671     DiskIo,
672     &AnchorPoint,
673     LastRecordedBlock,
674     (UINT64 *)StartingLBA,
675     (UINT64 *)EndingLBA
676     );
677 
678   return Status;
679 }
680 
681 /**
682   Install child handles if the Handle supports UDF/ECMA-167 volume format.
683 
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
691 
692 
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.
696 
697 **/
698 EFI_STATUS
PartitionInstallUdfChildHandles(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Handle,IN EFI_DISK_IO_PROTOCOL * DiskIo,IN EFI_DISK_IO2_PROTOCOL * DiskIo2,IN EFI_BLOCK_IO_PROTOCOL * BlockIo,IN EFI_BLOCK_IO2_PROTOCOL * BlockIo2,IN EFI_DEVICE_PATH_PROTOCOL * DevicePath)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
707   )
708 {
709   UINT32                       RemainderByMediaBlockSize;
710   EFI_STATUS                   Status;
711   EFI_BLOCK_IO_MEDIA           *Media;
712   EFI_PARTITION_INFO_PROTOCOL  PartitionInfo;
713   EFI_LBA                      StartingLBA;
714   EFI_LBA                      EndingLBA;
715   BOOLEAN                      ChildCreated;
716 
717   Media = BlockIo->Media;
718   ChildCreated = FALSE;
719 
720   //
721   // Check if UDF logical block size is multiple of underlying device block size
722   //
723   DivU64x32Remainder (
724     UDF_LOGICAL_SECTOR_SIZE,   // Dividend
725     Media->BlockSize,          // Divisor
726     &RemainderByMediaBlockSize // Remainder
727     );
728   if (RemainderByMediaBlockSize != 0) {
729     return EFI_NOT_FOUND;
730   }
731 
732   //
733   // Detect El Torito feature first.
734   // And always continue to search for UDF.
735   //
736   Status = PartitionInstallElToritoChildHandles (
737              This,
738              Handle,
739              DiskIo,
740              DiskIo2,
741              BlockIo,
742              BlockIo2,
743              DevicePath
744              );
745   if (!EFI_ERROR (Status)) {
746     DEBUG ((DEBUG_INFO, "PartitionDxe: El Torito standard found on handle 0x%p.\n", Handle));
747     ChildCreated = TRUE;
748   }
749 
750   //
751   // Search for an UDF file system on block device
752   //
753   Status = FindUdfFileSystem (BlockIo, DiskIo, &StartingLBA, &EndingLBA);
754   if (EFI_ERROR (Status)) {
755     return (ChildCreated ? EFI_SUCCESS : EFI_NOT_FOUND);
756   }
757 
758   //
759   // Create Partition Info protocol for UDF file system
760   //
761   ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
762   PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
763   PartitionInfo.Type = PARTITION_TYPE_OTHER;
764 
765   //
766   // Install partition child handle for UDF file system
767   //
768   Status = PartitionInstallChildHandle (
769     This,
770     Handle,
771     DiskIo,
772     DiskIo2,
773     BlockIo,
774     BlockIo2,
775     DevicePath,
776     (EFI_DEVICE_PATH_PROTOCOL *)&gUdfDevicePath,
777     &PartitionInfo,
778     StartingLBA,
779     EndingLBA,
780     Media->BlockSize,
781     NULL
782     );
783   if (EFI_ERROR (Status)) {
784     return (ChildCreated ? EFI_SUCCESS : Status);
785   }
786 
787   return EFI_SUCCESS;
788 }
789