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