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 Media Device Path for UDF file system
33 UDF_DEVICE_PATH gUdfDevicePath
= {
34 { { MEDIA_DEVICE_PATH
, MEDIA_VENDOR_DP
,
35 { sizeof (VENDOR_DEVICE_PATH
), 0 } },
36 EFI_UDF_DEVICE_PATH_GUID
38 { END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
,
39 { sizeof (EFI_DEVICE_PATH_PROTOCOL
), 0 }
44 FindAnchorVolumeDescriptorPointer (
45 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
46 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
47 OUT UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
*AnchorPoint
53 EFI_LBA DescriptorLBAs
[4];
56 BlockSize
= BlockIo
->Media
->BlockSize
;
57 EndLBA
= BlockIo
->Media
->LastBlock
;
58 DescriptorLBAs
[0] = 256;
59 DescriptorLBAs
[1] = EndLBA
- 256;
60 DescriptorLBAs
[2] = EndLBA
;
61 DescriptorLBAs
[3] = 512;
63 for (Index
= 0; Index
< ARRAY_SIZE (DescriptorLBAs
); Index
++) {
64 Status
= DiskIo
->ReadDisk (
66 BlockIo
->Media
->MediaId
,
67 MultU64x32 (DescriptorLBAs
[Index
], BlockSize
),
68 sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
),
71 if (EFI_ERROR (Status
)) {
75 // Check if read LBA has a valid AVDP descriptor.
77 if (IS_AVDP (AnchorPoint
)) {
84 return EFI_VOLUME_CORRUPTED
;
88 Check if block device supports a valid UDF file system as specified by OSTA
89 Universal Disk Format Specification 2.60.
91 @param[in] BlockIo BlockIo interface.
92 @param[in] DiskIo DiskIo interface.
94 @retval EFI_SUCCESS UDF file system found.
95 @retval EFI_UNSUPPORTED UDF file system not found.
96 @retval EFI_NO_MEDIA The device has no media.
97 @retval EFI_DEVICE_ERROR The device reported an error.
98 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
99 @retval EFI_OUT_OF_RESOURCES The scan was not successful due to lack of
104 SupportUdfFileSystem (
105 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
106 IN EFI_DISK_IO_PROTOCOL
*DiskIo
111 UINT64 EndDiskOffset
;
112 CDROM_VOLUME_DESCRIPTOR VolDescriptor
;
113 CDROM_VOLUME_DESCRIPTOR TerminatingVolDescriptor
;
114 UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER AnchorPoint
;
116 ZeroMem ((VOID
*)&TerminatingVolDescriptor
, sizeof (CDROM_VOLUME_DESCRIPTOR
));
119 // Start Volume Recognition Sequence
121 EndDiskOffset
= MultU64x32 (BlockIo
->Media
->LastBlock
,
122 BlockIo
->Media
->BlockSize
);
124 for (Offset
= UDF_VRS_START_OFFSET
; Offset
< EndDiskOffset
;
125 Offset
+= UDF_LOGICAL_SECTOR_SIZE
) {
127 // Check if block device has a Volume Structure Descriptor and an Extended
130 Status
= DiskIo
->ReadDisk (
132 BlockIo
->Media
->MediaId
,
134 sizeof (CDROM_VOLUME_DESCRIPTOR
),
135 (VOID
*)&VolDescriptor
137 if (EFI_ERROR (Status
)) {
141 if (CompareMem ((VOID
*)VolDescriptor
.Unknown
.Id
,
142 (VOID
*)UDF_BEA_IDENTIFIER
,
143 sizeof (VolDescriptor
.Unknown
.Id
)) == 0) {
147 if ((CompareMem ((VOID
*)VolDescriptor
.Unknown
.Id
,
149 sizeof (VolDescriptor
.Unknown
.Id
)) != 0) ||
150 (CompareMem ((VOID
*)&VolDescriptor
,
151 (VOID
*)&TerminatingVolDescriptor
,
152 sizeof (CDROM_VOLUME_DESCRIPTOR
)) == 0)) {
153 return EFI_UNSUPPORTED
;
158 // Look for "NSR0{2,3}" identifiers in the Extended Area.
160 Offset
+= UDF_LOGICAL_SECTOR_SIZE
;
161 if (Offset
>= EndDiskOffset
) {
162 return EFI_UNSUPPORTED
;
165 Status
= DiskIo
->ReadDisk (
167 BlockIo
->Media
->MediaId
,
169 sizeof (CDROM_VOLUME_DESCRIPTOR
),
170 (VOID
*)&VolDescriptor
172 if (EFI_ERROR (Status
)) {
176 if ((CompareMem ((VOID
*)VolDescriptor
.Unknown
.Id
,
177 (VOID
*)UDF_NSR2_IDENTIFIER
,
178 sizeof (VolDescriptor
.Unknown
.Id
)) != 0) &&
179 (CompareMem ((VOID
*)VolDescriptor
.Unknown
.Id
,
180 (VOID
*)UDF_NSR3_IDENTIFIER
,
181 sizeof (VolDescriptor
.Unknown
.Id
)) != 0)) {
182 return EFI_UNSUPPORTED
;
186 // Look for "TEA01" identifier in the Extended Area
188 Offset
+= UDF_LOGICAL_SECTOR_SIZE
;
189 if (Offset
>= EndDiskOffset
) {
190 return EFI_UNSUPPORTED
;
193 Status
= DiskIo
->ReadDisk (
195 BlockIo
->Media
->MediaId
,
197 sizeof (CDROM_VOLUME_DESCRIPTOR
),
198 (VOID
*)&VolDescriptor
200 if (EFI_ERROR (Status
)) {
204 if (CompareMem ((VOID
*)VolDescriptor
.Unknown
.Id
,
205 (VOID
*)UDF_TEA_IDENTIFIER
,
206 sizeof (VolDescriptor
.Unknown
.Id
)) != 0) {
207 return EFI_UNSUPPORTED
;
210 Status
= FindAnchorVolumeDescriptorPointer (BlockIo
, DiskIo
, &AnchorPoint
);
211 if (EFI_ERROR (Status
)) {
212 return EFI_UNSUPPORTED
;
219 Install child handles if the Handle supports UDF/ECMA-167 volume format.
221 @param[in] This Calling context.
222 @param[in] Handle Parent Handle.
223 @param[in] DiskIo Parent DiskIo interface.
224 @param[in] DiskIo2 Parent DiskIo2 interface.
225 @param[in] BlockIo Parent BlockIo interface.
226 @param[in] BlockIo2 Parent BlockIo2 interface.
227 @param[in] DevicePath Parent Device Path
230 @retval EFI_SUCCESS Child handle(s) was added.
231 @retval EFI_MEDIA_CHANGED Media changed Detected.
232 @retval other no child handle was added.
236 PartitionInstallUdfChildHandles (
237 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
238 IN EFI_HANDLE Handle
,
239 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
240 IN EFI_DISK_IO2_PROTOCOL
*DiskIo2
,
241 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
242 IN EFI_BLOCK_IO2_PROTOCOL
*BlockIo2
,
243 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
246 UINT32 RemainderByMediaBlockSize
;
248 EFI_BLOCK_IO_MEDIA
*Media
;
249 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
250 EFI_GUID
*VendorDefinedGuid
;
251 EFI_GUID UdfDevPathGuid
= EFI_UDF_DEVICE_PATH_GUID
;
252 EFI_PARTITION_INFO_PROTOCOL PartitionInfo
;
254 Media
= BlockIo
->Media
;
257 // Check if UDF logical block size is multiple of underlying device block size
260 UDF_LOGICAL_SECTOR_SIZE
, // Dividend
261 Media
->BlockSize
, // Divisor
262 &RemainderByMediaBlockSize
// Remainder
264 if (RemainderByMediaBlockSize
!= 0) {
265 return EFI_NOT_FOUND
;
268 DevicePathNode
= DevicePath
;
269 while (!IsDevicePathEnd (DevicePathNode
)) {
271 // Do not allow checking for UDF file systems in CDROM "El Torito"
272 // partitions, and skip duplicate installation of UDF file system child
275 if (DevicePathType (DevicePathNode
) == MEDIA_DEVICE_PATH
) {
276 if (DevicePathSubType (DevicePathNode
) == MEDIA_CDROM_DP
) {
277 return EFI_NOT_FOUND
;
279 if (DevicePathSubType (DevicePathNode
) == MEDIA_VENDOR_DP
) {
280 VendorDefinedGuid
= (EFI_GUID
*)((UINTN
)DevicePathNode
+
281 OFFSET_OF (VENDOR_DEVICE_PATH
, Guid
));
282 if (CompareGuid (VendorDefinedGuid
, &UdfDevPathGuid
)) {
283 return EFI_NOT_FOUND
;
288 // Try next device path node
290 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
294 // Check if block device supports an UDF file system
296 Status
= SupportUdfFileSystem (BlockIo
, DiskIo
);
297 if (EFI_ERROR (Status
)) {
298 return EFI_NOT_FOUND
;
302 // Create Partition Info protocol for UDF file system
304 ZeroMem (&PartitionInfo
, sizeof (EFI_PARTITION_INFO_PROTOCOL
));
305 PartitionInfo
.Revision
= EFI_PARTITION_INFO_PROTOCOL_REVISION
;
306 PartitionInfo
.Type
= PARTITION_TYPE_OTHER
;
309 // Install partition child handle for UDF file system
311 Status
= PartitionInstallChildHandle (
319 (EFI_DEVICE_PATH_PROTOCOL
*)&gUdfDevicePath
,
325 if (!EFI_ERROR (Status
)) {
326 Status
= EFI_NOT_FOUND
;