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