]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c
MdeModulePkg/UDF: Fix creation of UDF logical partition
[mirror_edk2.git] / MdeModulePkg / Universal / Disk / PartitionDxe / Udf.c
1 /** @file
2 Scan for an UDF file system on a formatted media.
3
4 Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
5
6 This program and the accompanying materials are licensed and made available
7 under the terms and conditions of the BSD License which accompanies this
8 distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
12 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 **/
14
15 #include "Partition.h"
16
17 //
18 // C5BD4D42-1A76-4996-8956-73CDA326CD0A
19 //
20 #define EFI_UDF_DEVICE_PATH_GUID \
21 { 0xC5BD4D42, 0x1A76, 0x4996, \
22 { 0x89, 0x56, 0x73, 0xCD, 0xA3, 0x26, 0xCD, 0x0A } \
23 }
24
25 typedef struct {
26 VENDOR_DEVICE_PATH DevicePath;
27 EFI_DEVICE_PATH_PROTOCOL End;
28 } UDF_DEVICE_PATH;
29
30 //
31 // Vendor-Defined Device Path GUID for UDF file system
32 //
33 EFI_GUID gUdfDevPathGuid = EFI_UDF_DEVICE_PATH_GUID;
34
35 //
36 // Vendor-Defined Media Device Path for UDF file system
37 //
38 UDF_DEVICE_PATH gUdfDevicePath = {
39 { { MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP,
40 { sizeof (VENDOR_DEVICE_PATH), 0 } },
41 EFI_UDF_DEVICE_PATH_GUID
42 },
43 { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
44 { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
45 }
46 };
47
48 /**
49 Find the anchor volume descriptor pointer.
50
51 @param[in] BlockIo BlockIo interface.
52 @param[in] DiskIo DiskIo interface.
53 @param[out] AnchorPoint Anchor volume descriptor pointer.
54
55 @retval EFI_SUCCESS Anchor volume descriptor pointer found.
56 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
57 @retval other Anchor volume descriptor pointer not found.
58
59 **/
60 EFI_STATUS
61 FindAnchorVolumeDescriptorPointer (
62 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
63 IN EFI_DISK_IO_PROTOCOL *DiskIo,
64 OUT UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoint
65 )
66 {
67 EFI_STATUS Status;
68 UINT32 BlockSize;
69 EFI_LBA EndLBA;
70 EFI_LBA DescriptorLBAs[4];
71 UINTN Index;
72 UDF_DESCRIPTOR_TAG *DescriptorTag;
73
74 BlockSize = BlockIo->Media->BlockSize;
75 EndLBA = BlockIo->Media->LastBlock;
76 DescriptorLBAs[0] = 256;
77 DescriptorLBAs[1] = EndLBA - 256;
78 DescriptorLBAs[2] = EndLBA;
79 DescriptorLBAs[3] = 512;
80
81 for (Index = 0; Index < ARRAY_SIZE (DescriptorLBAs); Index++) {
82 Status = DiskIo->ReadDisk (
83 DiskIo,
84 BlockIo->Media->MediaId,
85 MultU64x32 (DescriptorLBAs[Index], BlockSize),
86 sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER),
87 (VOID *)AnchorPoint
88 );
89 if (EFI_ERROR (Status)) {
90 return Status;
91 }
92
93 DescriptorTag = &AnchorPoint->DescriptorTag;
94
95 //
96 // Check if read LBA has a valid AVDP descriptor.
97 //
98 if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) {
99 return EFI_SUCCESS;
100 }
101 }
102 //
103 // No AVDP found.
104 //
105 return EFI_VOLUME_CORRUPTED;
106 }
107
108 /**
109 Find UDF volume identifiers in a Volume Recognition Sequence.
110
111 @param[in] BlockIo BlockIo interface.
112 @param[in] DiskIo DiskIo interface.
113
114 @retval EFI_SUCCESS UDF volume identifiers were found.
115 @retval EFI_NOT_FOUND UDF volume identifiers were not found.
116 @retval other Failed to perform disk I/O.
117
118 **/
119 EFI_STATUS
120 FindUdfVolumeIdentifiers (
121 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
122 IN EFI_DISK_IO_PROTOCOL *DiskIo
123 )
124 {
125 EFI_STATUS Status;
126 UINT64 Offset;
127 UINT64 EndDiskOffset;
128 CDROM_VOLUME_DESCRIPTOR VolDescriptor;
129 CDROM_VOLUME_DESCRIPTOR TerminatingVolDescriptor;
130
131 ZeroMem ((VOID *)&TerminatingVolDescriptor, sizeof (CDROM_VOLUME_DESCRIPTOR));
132
133 //
134 // Start Volume Recognition Sequence
135 //
136 EndDiskOffset = MultU64x32 (BlockIo->Media->LastBlock,
137 BlockIo->Media->BlockSize);
138
139 for (Offset = UDF_VRS_START_OFFSET; Offset < EndDiskOffset;
140 Offset += UDF_LOGICAL_SECTOR_SIZE) {
141 //
142 // Check if block device has a Volume Structure Descriptor and an Extended
143 // Area.
144 //
145 Status = DiskIo->ReadDisk (
146 DiskIo,
147 BlockIo->Media->MediaId,
148 Offset,
149 sizeof (CDROM_VOLUME_DESCRIPTOR),
150 (VOID *)&VolDescriptor
151 );
152 if (EFI_ERROR (Status)) {
153 return Status;
154 }
155
156 if (CompareMem ((VOID *)VolDescriptor.Unknown.Id,
157 (VOID *)UDF_BEA_IDENTIFIER,
158 sizeof (VolDescriptor.Unknown.Id)) == 0) {
159 break;
160 }
161
162 if ((CompareMem ((VOID *)VolDescriptor.Unknown.Id,
163 (VOID *)CDVOL_ID,
164 sizeof (VolDescriptor.Unknown.Id)) != 0) ||
165 (CompareMem ((VOID *)&VolDescriptor,
166 (VOID *)&TerminatingVolDescriptor,
167 sizeof (CDROM_VOLUME_DESCRIPTOR)) == 0)) {
168 return EFI_NOT_FOUND;
169 }
170 }
171
172 //
173 // Look for "NSR0{2,3}" identifiers in the Extended Area.
174 //
175 Offset += UDF_LOGICAL_SECTOR_SIZE;
176 if (Offset >= EndDiskOffset) {
177 return EFI_NOT_FOUND;
178 }
179
180 Status = DiskIo->ReadDisk (
181 DiskIo,
182 BlockIo->Media->MediaId,
183 Offset,
184 sizeof (CDROM_VOLUME_DESCRIPTOR),
185 (VOID *)&VolDescriptor
186 );
187 if (EFI_ERROR (Status)) {
188 return Status;
189 }
190
191 if ((CompareMem ((VOID *)VolDescriptor.Unknown.Id,
192 (VOID *)UDF_NSR2_IDENTIFIER,
193 sizeof (VolDescriptor.Unknown.Id)) != 0) &&
194 (CompareMem ((VOID *)VolDescriptor.Unknown.Id,
195 (VOID *)UDF_NSR3_IDENTIFIER,
196 sizeof (VolDescriptor.Unknown.Id)) != 0)) {
197 return EFI_NOT_FOUND;
198 }
199
200 //
201 // Look for "TEA01" identifier in the Extended Area
202 //
203 Offset += UDF_LOGICAL_SECTOR_SIZE;
204 if (Offset >= EndDiskOffset) {
205 return EFI_NOT_FOUND;
206 }
207
208 Status = DiskIo->ReadDisk (
209 DiskIo,
210 BlockIo->Media->MediaId,
211 Offset,
212 sizeof (CDROM_VOLUME_DESCRIPTOR),
213 (VOID *)&VolDescriptor
214 );
215 if (EFI_ERROR (Status)) {
216 return Status;
217 }
218
219 if (CompareMem ((VOID *)VolDescriptor.Unknown.Id,
220 (VOID *)UDF_TEA_IDENTIFIER,
221 sizeof (VolDescriptor.Unknown.Id)) != 0) {
222 return EFI_NOT_FOUND;
223 }
224
225 return EFI_SUCCESS;
226 }
227
228 /**
229 Check if Logical Volume Descriptor is supported by current EDK2 UDF file
230 system implementation.
231
232 @param[in] LogicalVolDesc Logical Volume Descriptor pointer.
233
234 @retval TRUE Logical Volume Descriptor is supported.
235 @retval FALSE Logical Volume Descriptor is not supported.
236
237 **/
238 BOOLEAN
239 IsLogicalVolumeDescriptorSupported (
240 UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc
241 )
242 {
243 //
244 // Check for a valid UDF revision range
245 //
246 switch (LogicalVolDesc->DomainIdentifier.Suffix.Domain.UdfRevision) {
247 case 0x0102:
248 case 0x0150:
249 case 0x0200:
250 case 0x0201:
251 case 0x0250:
252 case 0x0260:
253 break;
254 default:
255 return FALSE;
256 }
257
258 //
259 // Check for a single Partition Map
260 //
261 if (LogicalVolDesc->NumberOfPartitionMaps > 1) {
262 return FALSE;
263 }
264 //
265 // UDF 1.02 revision supports only Type 1 (Physical) partitions, but
266 // let's check it any way.
267 //
268 // PartitionMap[0] -> type
269 // PartitionMap[1] -> length (in bytes)
270 //
271 if (LogicalVolDesc->PartitionMaps[0] != 1 ||
272 LogicalVolDesc->PartitionMaps[1] != 6) {
273 return FALSE;
274 }
275
276 return TRUE;
277 }
278
279 /**
280 Find UDF logical volume location and whether it is supported by current EDK2
281 UDF file system implementation.
282
283 @param[in] BlockIo BlockIo interface.
284 @param[in] DiskIo DiskIo interface.
285 @param[in] AnchorPoint Anchor volume descriptor pointer.
286 @param[out] MainVdsStartBlock Main VDS starting block number.
287 @param[out] MainVdsEndBlock Main VDS ending block number.
288
289 @retval EFI_SUCCESS UDF logical volume was found.
290 @retval EFI_VOLUME_CORRUPTED UDF file system structures are corrupted.
291 @retval EFI_UNSUPPORTED UDF logical volume is not supported.
292 @retval other Failed to perform disk I/O.
293
294 **/
295 EFI_STATUS
296 FindLogicalVolumeLocation (
297 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
298 IN EFI_DISK_IO_PROTOCOL *DiskIo,
299 IN UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoint,
300 OUT UINT64 *MainVdsStartBlock,
301 OUT UINT64 *MainVdsEndBlock
302 )
303 {
304 EFI_STATUS Status;
305 UINT32 BlockSize;
306 EFI_LBA LastBlock;
307 UDF_EXTENT_AD *ExtentAd;
308 UINT64 SeqBlocksNum;
309 UINT64 SeqStartBlock;
310 UINT64 GuardMainVdsStartBlock;
311 VOID *Buffer;
312 UINT64 SeqEndBlock;
313 BOOLEAN StopSequence;
314 UINTN LvdsCount;
315 UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc;
316 UDF_DESCRIPTOR_TAG *DescriptorTag;
317
318 BlockSize = BlockIo->Media->BlockSize;
319 LastBlock = BlockIo->Media->LastBlock;
320 ExtentAd = &AnchorPoint->MainVolumeDescriptorSequenceExtent;
321
322 //
323 // UDF 2.60, 2.2.3.1 struct MainVolumeDescriptorSequenceExtent
324 //
325 // The Main Volume Descriptor Sequence Extent shall have a minimum length of
326 // 16 logical sectors.
327 //
328 // Also make sure it does not exceed maximum number of blocks in the disk.
329 //
330 SeqBlocksNum = DivU64x32 ((UINT64)ExtentAd->ExtentLength, BlockSize);
331 if (SeqBlocksNum < 16 || (EFI_LBA)SeqBlocksNum > LastBlock + 1) {
332 return EFI_VOLUME_CORRUPTED;
333 }
334
335 //
336 // Check for valid Volume Descriptor Sequence starting block number
337 //
338 SeqStartBlock = (UINT64)ExtentAd->ExtentLocation;
339 if (SeqStartBlock > LastBlock ||
340 SeqStartBlock + SeqBlocksNum - 1 > LastBlock) {
341 return EFI_VOLUME_CORRUPTED;
342 }
343
344 GuardMainVdsStartBlock = SeqStartBlock;
345
346 //
347 // Allocate buffer for reading disk blocks
348 //
349 Buffer = AllocateZeroPool ((UINTN)BlockSize);
350 if (Buffer == NULL) {
351 return EFI_OUT_OF_RESOURCES;
352 }
353
354 SeqEndBlock = SeqStartBlock + SeqBlocksNum;
355 StopSequence = FALSE;
356 LvdsCount = 0;
357 Status = EFI_VOLUME_CORRUPTED;
358 //
359 // Start Main Volume Descriptor Sequence
360 //
361 for (; SeqStartBlock < SeqEndBlock && !StopSequence; SeqStartBlock++) {
362 //
363 // Read disk block
364 //
365 Status = BlockIo->ReadBlocks (
366 BlockIo,
367 BlockIo->Media->MediaId,
368 SeqStartBlock,
369 BlockSize,
370 Buffer
371 );
372 if (EFI_ERROR (Status)) {
373 goto Out_Free;
374 }
375
376 DescriptorTag = Buffer;
377
378 //
379 // ECMA 167, 8.4.1 Contents of a Volume Descriptor Sequence
380 //
381 // - A Volume Descriptor Sequence shall contain one or more Primary Volume
382 // Descriptors.
383 // - A Volume Descriptor Sequence shall contain zero or more Implementation
384 // Use Volume Descriptors.
385 // - A Volume Descriptor Sequence shall contain zero or more Partition
386 // Descriptors.
387 // - A Volume Descriptor Sequence shall contain zero or more Logical Volume
388 // Descriptors.
389 // - A Volume Descriptor Sequence shall contain zero or more Unallocated
390 // Space Descriptors.
391 //
392 switch (DescriptorTag->TagIdentifier) {
393 case UdfPrimaryVolumeDescriptor:
394 case UdfImplemenationUseVolumeDescriptor:
395 case UdfPartitionDescriptor:
396 case UdfUnallocatedSpaceDescriptor:
397 break;
398
399 case UdfLogicalVolumeDescriptor:
400 LogicalVolDesc = Buffer;
401
402 //
403 // Check for existence of a single LVD and whether it is supported by
404 // current EDK2 UDF file system implementation.
405 //
406 if (++LvdsCount > 1 ||
407 !IsLogicalVolumeDescriptorSupported (LogicalVolDesc)) {
408 Status = EFI_UNSUPPORTED;
409 StopSequence = TRUE;
410 }
411
412 break;
413
414 case UdfTerminatingDescriptor:
415 //
416 // Stop the sequence when we find a Terminating Descriptor
417 // (aka Unallocated Sector), se we don't have to walk all the unallocated
418 // area unnecessarily.
419 //
420 StopSequence = TRUE;
421 break;
422
423 default:
424 //
425 // An invalid Volume Descriptor has been found in the sequece. Volume is
426 // corrupted.
427 //
428 Status = EFI_VOLUME_CORRUPTED;
429 goto Out_Free;
430 }
431 }
432
433 //
434 // Check if LVD was found
435 //
436 if (!EFI_ERROR (Status) && LvdsCount == 1) {
437 *MainVdsStartBlock = GuardMainVdsStartBlock;
438 //
439 // We do not need to read either LVD or PD descriptors to know the last
440 // valid block in the found UDF file system. It's already LastBlock.
441 //
442 *MainVdsEndBlock = LastBlock;
443
444 Status = EFI_SUCCESS;
445 }
446
447 Out_Free:
448 //
449 // Free block read buffer
450 //
451 FreePool (Buffer);
452
453 return Status;
454 }
455
456 /**
457 Find a supported UDF file system in block device.
458
459 @param[in] BlockIo BlockIo interface.
460 @param[in] DiskIo DiskIo interface.
461 @param[out] StartingLBA UDF file system starting LBA.
462 @param[out] EndingLBA UDF file system starting LBA.
463
464 @retval EFI_SUCCESS UDF file system was found.
465 @retval other UDF file system was not found.
466
467 **/
468 EFI_STATUS
469 FindUdfFileSystem (
470 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
471 IN EFI_DISK_IO_PROTOCOL *DiskIo,
472 OUT EFI_LBA *StartingLBA,
473 OUT EFI_LBA *EndingLBA
474 )
475 {
476 EFI_STATUS Status;
477 UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER AnchorPoint;
478
479 //
480 // Find UDF volume identifiers
481 //
482 Status = FindUdfVolumeIdentifiers (BlockIo, DiskIo);
483 if (EFI_ERROR (Status)) {
484 return Status;
485 }
486
487 //
488 // Find Anchor Volume Descriptor Pointer
489 //
490 Status = FindAnchorVolumeDescriptorPointer (BlockIo, DiskIo, &AnchorPoint);
491 if (EFI_ERROR (Status)) {
492 return Status;
493 }
494
495 //
496 // Find Logical Volume location
497 //
498 Status = FindLogicalVolumeLocation (
499 BlockIo,
500 DiskIo,
501 &AnchorPoint,
502 (UINT64 *)StartingLBA,
503 (UINT64 *)EndingLBA
504 );
505
506 return Status;
507 }
508
509 /**
510 Install child handles if the Handle supports UDF/ECMA-167 volume format.
511
512 @param[in] This Calling context.
513 @param[in] Handle Parent Handle.
514 @param[in] DiskIo Parent DiskIo interface.
515 @param[in] DiskIo2 Parent DiskIo2 interface.
516 @param[in] BlockIo Parent BlockIo interface.
517 @param[in] BlockIo2 Parent BlockIo2 interface.
518 @param[in] DevicePath Parent Device Path
519
520
521 @retval EFI_SUCCESS Child handle(s) was added.
522 @retval EFI_MEDIA_CHANGED Media changed Detected.
523 @retval other no child handle was added.
524
525 **/
526 EFI_STATUS
527 PartitionInstallUdfChildHandles (
528 IN EFI_DRIVER_BINDING_PROTOCOL *This,
529 IN EFI_HANDLE Handle,
530 IN EFI_DISK_IO_PROTOCOL *DiskIo,
531 IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
532 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
533 IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
534 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
535 )
536 {
537 UINT32 RemainderByMediaBlockSize;
538 EFI_STATUS Status;
539 EFI_BLOCK_IO_MEDIA *Media;
540 EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
541 EFI_LBA StartingLBA;
542 EFI_LBA EndingLBA;
543
544 Media = BlockIo->Media;
545
546 //
547 // Check if UDF logical block size is multiple of underlying device block size
548 //
549 DivU64x32Remainder (
550 UDF_LOGICAL_SECTOR_SIZE, // Dividend
551 Media->BlockSize, // Divisor
552 &RemainderByMediaBlockSize // Remainder
553 );
554 if (RemainderByMediaBlockSize != 0) {
555 return EFI_NOT_FOUND;
556 }
557
558 //
559 // Search for an UDF file system on block device
560 //
561 Status = FindUdfFileSystem (BlockIo, DiskIo, &StartingLBA, &EndingLBA);
562 if (EFI_ERROR (Status)) {
563 return EFI_NOT_FOUND;
564 }
565
566 //
567 // Create Partition Info protocol for UDF file system
568 //
569 ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
570 PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
571 PartitionInfo.Type = PARTITION_TYPE_OTHER;
572
573 //
574 // Install partition child handle for UDF file system
575 //
576 Status = PartitionInstallChildHandle (
577 This,
578 Handle,
579 DiskIo,
580 DiskIo2,
581 BlockIo,
582 BlockIo2,
583 DevicePath,
584 (EFI_DEVICE_PATH_PROTOCOL *)&gUdfDevicePath,
585 &PartitionInfo,
586 StartingLBA,
587 EndingLBA,
588 Media->BlockSize
589 );
590
591 return Status;
592 }