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