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