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