]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c
MdeModulePkg/Udf: Refine function description comments
[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 Media Device Path for UDF file system
32 //
33 UDF_DEVICE_PATH gUdfDevicePath = {
34 { { MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP,
35 { sizeof (VENDOR_DEVICE_PATH), 0 } },
36 EFI_UDF_DEVICE_PATH_GUID
37 },
38 { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
39 { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
40 }
41 };
42
43 /**
44 Find the anchor volume descriptor pointer.
45
46 @param[in] BlockIo BlockIo interface.
47 @param[in] DiskIo DiskIo interface.
48 @param[out] AnchorPoint Anchor volume descriptor pointer.
49
50 @retval EFI_SUCCESS Anchor volume descriptor pointer found.
51 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
52 @retval other Anchor volume descriptor pointer not found.
53
54 **/
55 EFI_STATUS
56 FindAnchorVolumeDescriptorPointer (
57 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
58 IN EFI_DISK_IO_PROTOCOL *DiskIo,
59 OUT UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoint
60 )
61 {
62 EFI_STATUS Status;
63 UINT32 BlockSize;
64 EFI_LBA EndLBA;
65 EFI_LBA DescriptorLBAs[4];
66 UINTN Index;
67
68 BlockSize = BlockIo->Media->BlockSize;
69 EndLBA = BlockIo->Media->LastBlock;
70 DescriptorLBAs[0] = 256;
71 DescriptorLBAs[1] = EndLBA - 256;
72 DescriptorLBAs[2] = EndLBA;
73 DescriptorLBAs[3] = 512;
74
75 for (Index = 0; Index < ARRAY_SIZE (DescriptorLBAs); Index++) {
76 Status = DiskIo->ReadDisk (
77 DiskIo,
78 BlockIo->Media->MediaId,
79 MultU64x32 (DescriptorLBAs[Index], BlockSize),
80 sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER),
81 (VOID *)AnchorPoint
82 );
83 if (EFI_ERROR (Status)) {
84 return Status;
85 }
86 //
87 // Check if read LBA has a valid AVDP descriptor.
88 //
89 if (IS_AVDP (AnchorPoint)) {
90 return EFI_SUCCESS;
91 }
92 }
93 //
94 // No AVDP found.
95 //
96 return EFI_VOLUME_CORRUPTED;
97 }
98
99 /**
100 Check if block device supports a valid UDF file system as specified by OSTA
101 Universal Disk Format Specification 2.60.
102
103 @param[in] BlockIo BlockIo interface.
104 @param[in] DiskIo DiskIo interface.
105
106 @retval EFI_SUCCESS UDF file system found.
107 @retval EFI_UNSUPPORTED UDF file system not found.
108 @retval EFI_NO_MEDIA The device has no media.
109 @retval EFI_DEVICE_ERROR The device reported an error.
110 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
111 @retval EFI_OUT_OF_RESOURCES The scan was not successful due to lack of
112 resources.
113
114 **/
115 EFI_STATUS
116 SupportUdfFileSystem (
117 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
118 IN EFI_DISK_IO_PROTOCOL *DiskIo
119 )
120 {
121 EFI_STATUS Status;
122 UINT64 Offset;
123 UINT64 EndDiskOffset;
124 CDROM_VOLUME_DESCRIPTOR VolDescriptor;
125 CDROM_VOLUME_DESCRIPTOR TerminatingVolDescriptor;
126 UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER AnchorPoint;
127
128 ZeroMem ((VOID *)&TerminatingVolDescriptor, sizeof (CDROM_VOLUME_DESCRIPTOR));
129
130 //
131 // Start Volume Recognition Sequence
132 //
133 EndDiskOffset = MultU64x32 (BlockIo->Media->LastBlock,
134 BlockIo->Media->BlockSize);
135
136 for (Offset = UDF_VRS_START_OFFSET; Offset < EndDiskOffset;
137 Offset += UDF_LOGICAL_SECTOR_SIZE) {
138 //
139 // Check if block device has a Volume Structure Descriptor and an Extended
140 // Area.
141 //
142 Status = DiskIo->ReadDisk (
143 DiskIo,
144 BlockIo->Media->MediaId,
145 Offset,
146 sizeof (CDROM_VOLUME_DESCRIPTOR),
147 (VOID *)&VolDescriptor
148 );
149 if (EFI_ERROR (Status)) {
150 return Status;
151 }
152
153 if (CompareMem ((VOID *)VolDescriptor.Unknown.Id,
154 (VOID *)UDF_BEA_IDENTIFIER,
155 sizeof (VolDescriptor.Unknown.Id)) == 0) {
156 break;
157 }
158
159 if ((CompareMem ((VOID *)VolDescriptor.Unknown.Id,
160 (VOID *)CDVOL_ID,
161 sizeof (VolDescriptor.Unknown.Id)) != 0) ||
162 (CompareMem ((VOID *)&VolDescriptor,
163 (VOID *)&TerminatingVolDescriptor,
164 sizeof (CDROM_VOLUME_DESCRIPTOR)) == 0)) {
165 return EFI_UNSUPPORTED;
166 }
167 }
168
169 //
170 // Look for "NSR0{2,3}" identifiers in the Extended Area.
171 //
172 Offset += UDF_LOGICAL_SECTOR_SIZE;
173 if (Offset >= EndDiskOffset) {
174 return EFI_UNSUPPORTED;
175 }
176
177 Status = DiskIo->ReadDisk (
178 DiskIo,
179 BlockIo->Media->MediaId,
180 Offset,
181 sizeof (CDROM_VOLUME_DESCRIPTOR),
182 (VOID *)&VolDescriptor
183 );
184 if (EFI_ERROR (Status)) {
185 return Status;
186 }
187
188 if ((CompareMem ((VOID *)VolDescriptor.Unknown.Id,
189 (VOID *)UDF_NSR2_IDENTIFIER,
190 sizeof (VolDescriptor.Unknown.Id)) != 0) &&
191 (CompareMem ((VOID *)VolDescriptor.Unknown.Id,
192 (VOID *)UDF_NSR3_IDENTIFIER,
193 sizeof (VolDescriptor.Unknown.Id)) != 0)) {
194 return EFI_UNSUPPORTED;
195 }
196
197 //
198 // Look for "TEA01" identifier in the Extended Area
199 //
200 Offset += UDF_LOGICAL_SECTOR_SIZE;
201 if (Offset >= EndDiskOffset) {
202 return EFI_UNSUPPORTED;
203 }
204
205 Status = DiskIo->ReadDisk (
206 DiskIo,
207 BlockIo->Media->MediaId,
208 Offset,
209 sizeof (CDROM_VOLUME_DESCRIPTOR),
210 (VOID *)&VolDescriptor
211 );
212 if (EFI_ERROR (Status)) {
213 return Status;
214 }
215
216 if (CompareMem ((VOID *)VolDescriptor.Unknown.Id,
217 (VOID *)UDF_TEA_IDENTIFIER,
218 sizeof (VolDescriptor.Unknown.Id)) != 0) {
219 return EFI_UNSUPPORTED;
220 }
221
222 Status = FindAnchorVolumeDescriptorPointer (BlockIo, DiskIo, &AnchorPoint);
223 if (EFI_ERROR (Status)) {
224 return EFI_UNSUPPORTED;
225 }
226
227 return EFI_SUCCESS;
228 }
229
230 /**
231 Install child handles if the Handle supports UDF/ECMA-167 volume format.
232
233 @param[in] This Calling context.
234 @param[in] Handle Parent Handle.
235 @param[in] DiskIo Parent DiskIo interface.
236 @param[in] DiskIo2 Parent DiskIo2 interface.
237 @param[in] BlockIo Parent BlockIo interface.
238 @param[in] BlockIo2 Parent BlockIo2 interface.
239 @param[in] DevicePath Parent Device Path
240
241
242 @retval EFI_SUCCESS Child handle(s) was added.
243 @retval EFI_MEDIA_CHANGED Media changed Detected.
244 @retval other no child handle was added.
245
246 **/
247 EFI_STATUS
248 PartitionInstallUdfChildHandles (
249 IN EFI_DRIVER_BINDING_PROTOCOL *This,
250 IN EFI_HANDLE Handle,
251 IN EFI_DISK_IO_PROTOCOL *DiskIo,
252 IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
253 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
254 IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
255 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
256 )
257 {
258 UINT32 RemainderByMediaBlockSize;
259 EFI_STATUS Status;
260 EFI_BLOCK_IO_MEDIA *Media;
261 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
262 EFI_GUID *VendorDefinedGuid;
263 EFI_GUID UdfDevPathGuid = EFI_UDF_DEVICE_PATH_GUID;
264 EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
265
266 Media = BlockIo->Media;
267
268 //
269 // Check if UDF logical block size is multiple of underlying device block size
270 //
271 DivU64x32Remainder (
272 UDF_LOGICAL_SECTOR_SIZE, // Dividend
273 Media->BlockSize, // Divisor
274 &RemainderByMediaBlockSize // Remainder
275 );
276 if (RemainderByMediaBlockSize != 0) {
277 return EFI_NOT_FOUND;
278 }
279
280 DevicePathNode = DevicePath;
281 while (!IsDevicePathEnd (DevicePathNode)) {
282 //
283 // Do not allow checking for UDF file systems in CDROM "El Torito"
284 // partitions, and skip duplicate installation of UDF file system child
285 // nodes.
286 //
287 if (DevicePathType (DevicePathNode) == MEDIA_DEVICE_PATH) {
288 if (DevicePathSubType (DevicePathNode) == MEDIA_CDROM_DP) {
289 return EFI_NOT_FOUND;
290 }
291 if (DevicePathSubType (DevicePathNode) == MEDIA_VENDOR_DP) {
292 VendorDefinedGuid = (EFI_GUID *)((UINTN)DevicePathNode +
293 OFFSET_OF (VENDOR_DEVICE_PATH, Guid));
294 if (CompareGuid (VendorDefinedGuid, &UdfDevPathGuid)) {
295 return EFI_NOT_FOUND;
296 }
297 }
298 }
299 //
300 // Try next device path node
301 //
302 DevicePathNode = NextDevicePathNode (DevicePathNode);
303 }
304
305 //
306 // Check if block device supports an UDF file system
307 //
308 Status = SupportUdfFileSystem (BlockIo, DiskIo);
309 if (EFI_ERROR (Status)) {
310 return EFI_NOT_FOUND;
311 }
312
313 //
314 // Create Partition Info protocol for UDF file system
315 //
316 ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
317 PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
318 PartitionInfo.Type = PARTITION_TYPE_OTHER;
319
320 //
321 // Install partition child handle for UDF file system
322 //
323 Status = PartitionInstallChildHandle (
324 This,
325 Handle,
326 DiskIo,
327 DiskIo2,
328 BlockIo,
329 BlockIo2,
330 DevicePath,
331 (EFI_DEVICE_PATH_PROTOCOL *)&gUdfDevicePath,
332 &PartitionInfo,
333 0,
334 Media->LastBlock,
335 Media->BlockSize
336 );
337 if (!EFI_ERROR (Status)) {
338 Status = EFI_NOT_FOUND;
339 }
340
341 return Status;
342 }