2 Scan for an UDF file system on a formatted media.
4 Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
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
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.
15 #include "Partition.h"
18 // C5BD4D42-1A76-4996-8956-73CDA326CD0A
20 #define EFI_UDF_DEVICE_PATH_GUID \
21 { 0xC5BD4D42, 0x1A76, 0x4996, \
22 { 0x89, 0x56, 0x73, 0xCD, 0xA3, 0x26, 0xCD, 0x0A } \
26 VENDOR_DEVICE_PATH DevicePath
;
27 EFI_DEVICE_PATH_PROTOCOL End
;
31 // Vendor-Defined Device Path GUID for UDF file system
33 EFI_GUID gUdfDevPathGuid
= EFI_UDF_DEVICE_PATH_GUID
;
36 // Vendor-Defined Media Device Path for UDF file system
38 UDF_DEVICE_PATH gUdfDevicePath
= {
39 { { MEDIA_DEVICE_PATH
, MEDIA_VENDOR_DP
,
40 { sizeof (VENDOR_DEVICE_PATH
), 0 } },
41 EFI_UDF_DEVICE_PATH_GUID
43 { END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
,
44 { sizeof (EFI_DEVICE_PATH_PROTOCOL
), 0 }
49 Find the anchor volume descriptor pointer.
51 @param[in] BlockIo BlockIo interface.
52 @param[in] DiskIo DiskIo interface.
53 @param[out] AnchorPoint Anchor volume descriptor pointer.
55 @retval EFI_SUCCESS Anchor volume descriptor pointer found.
56 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
57 @retval other Anchor volume descriptor pointer not found.
61 FindAnchorVolumeDescriptorPointer (
62 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
63 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
64 OUT UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
*AnchorPoint
70 EFI_LBA DescriptorLBAs
[4];
73 BlockSize
= BlockIo
->Media
->BlockSize
;
74 EndLBA
= BlockIo
->Media
->LastBlock
;
75 DescriptorLBAs
[0] = 256;
76 DescriptorLBAs
[1] = EndLBA
- 256;
77 DescriptorLBAs
[2] = EndLBA
;
78 DescriptorLBAs
[3] = 512;
80 for (Index
= 0; Index
< ARRAY_SIZE (DescriptorLBAs
); Index
++) {
81 Status
= DiskIo
->ReadDisk (
83 BlockIo
->Media
->MediaId
,
84 MultU64x32 (DescriptorLBAs
[Index
], BlockSize
),
85 sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
),
88 if (EFI_ERROR (Status
)) {
92 // Check if read LBA has a valid AVDP descriptor.
94 if (IS_AVDP (AnchorPoint
)) {
101 return EFI_VOLUME_CORRUPTED
;
105 Check if block device supports a valid UDF file system as specified by OSTA
106 Universal Disk Format Specification 2.60.
108 @param[in] BlockIo BlockIo interface.
109 @param[in] DiskIo DiskIo interface.
111 @retval EFI_SUCCESS UDF file system found.
112 @retval EFI_UNSUPPORTED UDF file system not found.
113 @retval EFI_NO_MEDIA The device has no media.
114 @retval EFI_DEVICE_ERROR The device reported an error.
115 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
116 @retval EFI_OUT_OF_RESOURCES The scan was not successful due to lack of
121 SupportUdfFileSystem (
122 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
123 IN EFI_DISK_IO_PROTOCOL
*DiskIo
128 UINT64 EndDiskOffset
;
129 CDROM_VOLUME_DESCRIPTOR VolDescriptor
;
130 CDROM_VOLUME_DESCRIPTOR TerminatingVolDescriptor
;
131 UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER AnchorPoint
;
133 ZeroMem ((VOID
*)&TerminatingVolDescriptor
, sizeof (CDROM_VOLUME_DESCRIPTOR
));
136 // Start Volume Recognition Sequence
138 EndDiskOffset
= MultU64x32 (BlockIo
->Media
->LastBlock
,
139 BlockIo
->Media
->BlockSize
);
141 for (Offset
= UDF_VRS_START_OFFSET
; Offset
< EndDiskOffset
;
142 Offset
+= UDF_LOGICAL_SECTOR_SIZE
) {
144 // Check if block device has a Volume Structure Descriptor and an Extended
147 Status
= DiskIo
->ReadDisk (
149 BlockIo
->Media
->MediaId
,
151 sizeof (CDROM_VOLUME_DESCRIPTOR
),
152 (VOID
*)&VolDescriptor
154 if (EFI_ERROR (Status
)) {
158 if (CompareMem ((VOID
*)VolDescriptor
.Unknown
.Id
,
159 (VOID
*)UDF_BEA_IDENTIFIER
,
160 sizeof (VolDescriptor
.Unknown
.Id
)) == 0) {
164 if ((CompareMem ((VOID
*)VolDescriptor
.Unknown
.Id
,
166 sizeof (VolDescriptor
.Unknown
.Id
)) != 0) ||
167 (CompareMem ((VOID
*)&VolDescriptor
,
168 (VOID
*)&TerminatingVolDescriptor
,
169 sizeof (CDROM_VOLUME_DESCRIPTOR
)) == 0)) {
170 return EFI_UNSUPPORTED
;
175 // Look for "NSR0{2,3}" identifiers in the Extended Area.
177 Offset
+= UDF_LOGICAL_SECTOR_SIZE
;
178 if (Offset
>= EndDiskOffset
) {
179 return EFI_UNSUPPORTED
;
182 Status
= DiskIo
->ReadDisk (
184 BlockIo
->Media
->MediaId
,
186 sizeof (CDROM_VOLUME_DESCRIPTOR
),
187 (VOID
*)&VolDescriptor
189 if (EFI_ERROR (Status
)) {
193 if ((CompareMem ((VOID
*)VolDescriptor
.Unknown
.Id
,
194 (VOID
*)UDF_NSR2_IDENTIFIER
,
195 sizeof (VolDescriptor
.Unknown
.Id
)) != 0) &&
196 (CompareMem ((VOID
*)VolDescriptor
.Unknown
.Id
,
197 (VOID
*)UDF_NSR3_IDENTIFIER
,
198 sizeof (VolDescriptor
.Unknown
.Id
)) != 0)) {
199 return EFI_UNSUPPORTED
;
203 // Look for "TEA01" identifier in the Extended Area
205 Offset
+= UDF_LOGICAL_SECTOR_SIZE
;
206 if (Offset
>= EndDiskOffset
) {
207 return EFI_UNSUPPORTED
;
210 Status
= DiskIo
->ReadDisk (
212 BlockIo
->Media
->MediaId
,
214 sizeof (CDROM_VOLUME_DESCRIPTOR
),
215 (VOID
*)&VolDescriptor
217 if (EFI_ERROR (Status
)) {
221 if (CompareMem ((VOID
*)VolDescriptor
.Unknown
.Id
,
222 (VOID
*)UDF_TEA_IDENTIFIER
,
223 sizeof (VolDescriptor
.Unknown
.Id
)) != 0) {
224 return EFI_UNSUPPORTED
;
227 Status
= FindAnchorVolumeDescriptorPointer (BlockIo
, DiskIo
, &AnchorPoint
);
228 if (EFI_ERROR (Status
)) {
229 return EFI_UNSUPPORTED
;
236 Install child handles if the Handle supports UDF/ECMA-167 volume format.
238 @param[in] This Calling context.
239 @param[in] Handle Parent Handle.
240 @param[in] DiskIo Parent DiskIo interface.
241 @param[in] DiskIo2 Parent DiskIo2 interface.
242 @param[in] BlockIo Parent BlockIo interface.
243 @param[in] BlockIo2 Parent BlockIo2 interface.
244 @param[in] DevicePath Parent Device Path
247 @retval EFI_SUCCESS Child handle(s) was added.
248 @retval EFI_MEDIA_CHANGED Media changed Detected.
249 @retval other no child handle was added.
253 PartitionInstallUdfChildHandles (
254 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
255 IN EFI_HANDLE Handle
,
256 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
257 IN EFI_DISK_IO2_PROTOCOL
*DiskIo2
,
258 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
259 IN EFI_BLOCK_IO2_PROTOCOL
*BlockIo2
,
260 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
263 UINT32 RemainderByMediaBlockSize
;
265 EFI_BLOCK_IO_MEDIA
*Media
;
266 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
267 EFI_GUID
*VendorDefinedGuid
;
268 EFI_PARTITION_INFO_PROTOCOL PartitionInfo
;
270 Media
= BlockIo
->Media
;
273 // Check if UDF logical block size is multiple of underlying device block size
276 UDF_LOGICAL_SECTOR_SIZE
, // Dividend
277 Media
->BlockSize
, // Divisor
278 &RemainderByMediaBlockSize
// Remainder
280 if (RemainderByMediaBlockSize
!= 0) {
281 return EFI_NOT_FOUND
;
284 DevicePathNode
= DevicePath
;
285 while (!IsDevicePathEnd (DevicePathNode
)) {
287 // Do not allow checking for UDF file systems in CDROM "El Torito"
288 // partitions, and skip duplicate installation of UDF file system child
291 if (DevicePathType (DevicePathNode
) == MEDIA_DEVICE_PATH
) {
292 if (DevicePathSubType (DevicePathNode
) == MEDIA_CDROM_DP
) {
293 return EFI_NOT_FOUND
;
295 if (DevicePathSubType (DevicePathNode
) == MEDIA_VENDOR_DP
) {
296 VendorDefinedGuid
= (EFI_GUID
*)((UINTN
)DevicePathNode
+
297 OFFSET_OF (VENDOR_DEVICE_PATH
, Guid
));
298 if (CompareGuid (VendorDefinedGuid
, &gUdfDevPathGuid
)) {
299 return EFI_NOT_FOUND
;
304 // Try next device path node
306 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
310 // Check if block device supports an UDF file system
312 Status
= SupportUdfFileSystem (BlockIo
, DiskIo
);
313 if (EFI_ERROR (Status
)) {
314 return EFI_NOT_FOUND
;
318 // Create Partition Info protocol for UDF file system
320 ZeroMem (&PartitionInfo
, sizeof (EFI_PARTITION_INFO_PROTOCOL
));
321 PartitionInfo
.Revision
= EFI_PARTITION_INFO_PROTOCOL_REVISION
;
322 PartitionInfo
.Type
= PARTITION_TYPE_OTHER
;
325 // Install partition child handle for UDF file system
327 Status
= PartitionInstallChildHandle (
335 (EFI_DEVICE_PATH_PROTOCOL
*)&gUdfDevicePath
,
341 if (!EFI_ERROR (Status
)) {
342 Status
= EFI_NOT_FOUND
;