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