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