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