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