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
51 UINT32 BlockSize
= BlockIo
->Media
->BlockSize
;
52 EFI_LBA EndLBA
= BlockIo
->Media
->LastBlock
;
53 EFI_LBA DescriptorLBAs
[] = { 256, EndLBA
- 256, EndLBA
, 512 };
56 for (Index
= 0; Index
< ARRAY_SIZE (DescriptorLBAs
); Index
++) {
57 Status
= DiskIo
->ReadDisk (
59 BlockIo
->Media
->MediaId
,
60 MultU64x32 (DescriptorLBAs
[Index
], BlockSize
),
61 sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
),
64 if (EFI_ERROR (Status
)) {
68 // Check if read LBA has a valid AVDP descriptor.
70 if (IS_AVDP (AnchorPoint
)) {
77 return EFI_VOLUME_CORRUPTED
;
81 Check if block device supports a valid UDF file system as specified by OSTA
82 Universal Disk Format Specification 2.60.
84 @param[in] BlockIo BlockIo interface.
85 @param[in] DiskIo DiskIo interface.
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
97 SupportUdfFileSystem (
98 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
99 IN EFI_DISK_IO_PROTOCOL
*DiskIo
104 UINT64 EndDiskOffset
;
105 CDROM_VOLUME_DESCRIPTOR VolDescriptor
;
106 CDROM_VOLUME_DESCRIPTOR TerminatingVolDescriptor
;
107 UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER AnchorPoint
;
109 ZeroMem ((VOID
*)&TerminatingVolDescriptor
, sizeof (CDROM_VOLUME_DESCRIPTOR
));
112 // Start Volume Recognition Sequence
114 EndDiskOffset
= MultU64x32 (BlockIo
->Media
->LastBlock
,
115 BlockIo
->Media
->BlockSize
);
117 for (Offset
= UDF_VRS_START_OFFSET
; Offset
< EndDiskOffset
;
118 Offset
+= UDF_LOGICAL_SECTOR_SIZE
) {
120 // Check if block device has a Volume Structure Descriptor and an Extended
123 Status
= DiskIo
->ReadDisk (
125 BlockIo
->Media
->MediaId
,
127 sizeof (CDROM_VOLUME_DESCRIPTOR
),
128 (VOID
*)&VolDescriptor
130 if (EFI_ERROR (Status
)) {
134 if (CompareMem ((VOID
*)VolDescriptor
.Unknown
.Id
,
135 (VOID
*)UDF_BEA_IDENTIFIER
,
136 sizeof (VolDescriptor
.Unknown
.Id
)) == 0) {
140 if ((CompareMem ((VOID
*)VolDescriptor
.Unknown
.Id
,
142 sizeof (VolDescriptor
.Unknown
.Id
)) != 0) ||
143 (CompareMem ((VOID
*)&VolDescriptor
,
144 (VOID
*)&TerminatingVolDescriptor
,
145 sizeof (CDROM_VOLUME_DESCRIPTOR
)) == 0)) {
146 return EFI_UNSUPPORTED
;
151 // Look for "NSR0{2,3}" identifiers in the Extended Area.
153 Offset
+= UDF_LOGICAL_SECTOR_SIZE
;
154 if (Offset
>= EndDiskOffset
) {
155 return EFI_UNSUPPORTED
;
158 Status
= DiskIo
->ReadDisk (
160 BlockIo
->Media
->MediaId
,
162 sizeof (CDROM_VOLUME_DESCRIPTOR
),
163 (VOID
*)&VolDescriptor
165 if (EFI_ERROR (Status
)) {
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
;
179 // Look for "TEA01" identifier in the Extended Area
181 Offset
+= UDF_LOGICAL_SECTOR_SIZE
;
182 if (Offset
>= EndDiskOffset
) {
183 return EFI_UNSUPPORTED
;
186 Status
= DiskIo
->ReadDisk (
188 BlockIo
->Media
->MediaId
,
190 sizeof (CDROM_VOLUME_DESCRIPTOR
),
191 (VOID
*)&VolDescriptor
193 if (EFI_ERROR (Status
)) {
197 if (CompareMem ((VOID
*)VolDescriptor
.Unknown
.Id
,
198 (VOID
*)UDF_TEA_IDENTIFIER
,
199 sizeof (VolDescriptor
.Unknown
.Id
)) != 0) {
200 return EFI_UNSUPPORTED
;
203 Status
= FindAnchorVolumeDescriptorPointer (BlockIo
, DiskIo
, &AnchorPoint
);
204 if (EFI_ERROR (Status
)) {
205 return EFI_UNSUPPORTED
;
212 Install child handles if the Handle supports UDF/ECMA-167 volume format.
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
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.
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
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
;
246 Media
= BlockIo
->Media
;
249 // Check if UDF logical block size is multiple of underlying device block size
251 if ((UDF_LOGICAL_SECTOR_SIZE
% Media
->BlockSize
) != 0 ||
252 Media
->BlockSize
> UDF_LOGICAL_SECTOR_SIZE
) {
253 return EFI_NOT_FOUND
;
256 DevicePathNode
= DevicePath
;
257 while (!IsDevicePathEnd (DevicePathNode
)) {
259 // Do not allow checking for UDF file systems in CDROM "El Torito"
260 // partitions, and skip duplicate installation of UDF file system child
263 if (DevicePathType (DevicePathNode
) == MEDIA_DEVICE_PATH
) {
264 if (DevicePathSubType (DevicePathNode
) == MEDIA_CDROM_DP
) {
265 return EFI_NOT_FOUND
;
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
;
276 // Try next device path node
278 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
282 // Check if block device supports an UDF file system
284 Status
= SupportUdfFileSystem (BlockIo
, DiskIo
);
285 if (EFI_ERROR (Status
)) {
286 return EFI_NOT_FOUND
;
290 // Create Partition Info protocol for UDF file system
292 ZeroMem (&PartitionInfo
, sizeof (EFI_PARTITION_INFO_PROTOCOL
));
293 PartitionInfo
.Revision
= EFI_PARTITION_INFO_PROTOCOL_REVISION
;
294 PartitionInfo
.Type
= PARTITION_TYPE_OTHER
;
297 // Install partition child handle for UDF file system
299 Status
= PartitionInstallChildHandle (
307 (EFI_DEVICE_PATH_PROTOCOL
*)&gUdfDevicePath
,
313 if (!EFI_ERROR (Status
)) {
314 Status
= EFI_NOT_FOUND
;