2 Decode an El Torito formatted CD-ROM
4 Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
5 Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "Partition.h"
13 Install child handles if the Handle supports El Torito format.
15 @param[in] This Calling context.
16 @param[in] Handle Parent Handle.
17 @param[in] DiskIo Parent DiskIo interface.
18 @param[in] DiskIo2 Parent DiskIo2 interface.
19 @param[in] BlockIo Parent BlockIo interface.
20 @param[in] BlockIo2 Parent BlockIo2 interface.
21 @param[in] DevicePath Parent Device Path
24 @retval EFI_SUCCESS Child handle(s) was added.
25 @retval EFI_MEDIA_CHANGED Media changed Detected.
26 @retval other no child handle was added.
30 PartitionInstallElToritoChildHandles (
31 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
33 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
34 IN EFI_DISK_IO2_PROTOCOL
*DiskIo2
,
35 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
36 IN EFI_BLOCK_IO2_PROTOCOL
*BlockIo2
,
37 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
41 UINT64 VolDescriptorOffset
;
43 EFI_BLOCK_IO_MEDIA
*Media
;
44 CDROM_VOLUME_DESCRIPTOR
*VolDescriptor
;
45 ELTORITO_CATALOG
*Catalog
;
51 CDROM_DEVICE_PATH CdDev
;
56 EFI_PARTITION_INFO_PROTOCOL PartitionInfo
;
58 Found
= EFI_NOT_FOUND
;
59 Media
= BlockIo
->Media
;
64 // CD_ROM has the fixed block size as 2048 bytes (SIZE_2KB)
67 // If the ISO image has been copied onto a different storage media
68 // then the block size might be different (eg: USB).
69 // Ensure 2048 (SIZE_2KB) is a multiple of block size
70 if (((SIZE_2KB
% Media
->BlockSize
) != 0) || (Media
->BlockSize
> SIZE_2KB
)) {
74 VolDescriptor
= AllocatePool ((UINTN
)SIZE_2KB
);
76 if (VolDescriptor
== NULL
) {
80 Catalog
= (ELTORITO_CATALOG
*)VolDescriptor
;
83 // Loop: handle one volume descriptor per time
84 // The ISO-9660 volume descriptor starts at 32k on the media
86 for (VolDescriptorOffset
= SIZE_32KB
;
87 VolDescriptorOffset
<= MultU64x32 (Media
->LastBlock
, Media
->BlockSize
);
88 VolDescriptorOffset
+= SIZE_2KB
)
90 Status
= DiskIo
->ReadDisk (
97 if (EFI_ERROR (Status
)) {
103 // Check for valid volume descriptor signature
105 if ((VolDescriptor
->Unknown
.Type
== CDVOL_TYPE_END
) ||
106 (CompareMem (VolDescriptor
->Unknown
.Id
, CDVOL_ID
, sizeof (VolDescriptor
->Unknown
.Id
)) != 0)
110 // end of Volume descriptor list
116 // Read the Volume Space Size from Primary Volume Descriptor 81-88 byte,
117 // the 32-bit numerical values is stored in Both-byte orders
119 if (VolDescriptor
->PrimaryVolume
.Type
== CDVOL_TYPE_CODED
) {
120 VolSpaceSize
= VolDescriptor
->PrimaryVolume
.VolSpaceSize
[0];
124 // Is it an El Torito volume descriptor?
126 if (CompareMem (VolDescriptor
->BootRecordVolume
.SystemId
, CDVOL_ELTORITO_ID
, sizeof (CDVOL_ELTORITO_ID
) - 1) != 0) {
131 // Read in the boot El Torito boot catalog
132 // The LBA unit used by El Torito boot catalog is 2KB unit
134 Lba2KB
= UNPACK_INT32 (VolDescriptor
->BootRecordVolume
.EltCatalog
);
135 // Ensure the LBA (in 2KB unit) fits into our media
136 if (Lba2KB
* (SIZE_2KB
/ Media
->BlockSize
) > Media
->LastBlock
) {
140 Status
= DiskIo
->ReadDisk (
143 MultU64x32 (Lba2KB
, SIZE_2KB
),
147 if (EFI_ERROR (Status
)) {
148 DEBUG ((DEBUG_ERROR
, "EltCheckDevice: error reading catalog %r\n", Status
));
153 // We don't care too much about the Catalog header's contents, but we do want
154 // to make sure it looks like a Catalog header
156 if ((Catalog
->Catalog
.Indicator
!= ELTORITO_ID_CATALOG
) || (Catalog
->Catalog
.Id55AA
!= 0xAA55)) {
157 DEBUG ((DEBUG_ERROR
, "EltCheckBootCatalog: El Torito boot catalog header IDs not correct\n"));
162 CheckBuffer
= (UINT16
*)Catalog
;
163 for (Index
= 0; Index
< sizeof (ELTORITO_CATALOG
) / sizeof (UINT16
); Index
+= 1) {
164 Check
+= CheckBuffer
[Index
];
167 if ((Check
& 0xFFFF) != 0) {
168 DEBUG ((DEBUG_ERROR
, "EltCheckBootCatalog: El Torito boot catalog header checksum failed\n"));
172 MaxIndex
= Media
->BlockSize
/ sizeof (ELTORITO_CATALOG
);
173 for (Index
= 1, BootEntry
= 1; Index
< MaxIndex
; Index
+= 1) {
182 if ((Catalog
->Boot
.Indicator
!= ELTORITO_ID_SECTION_BOOTABLE
) || (Catalog
->Boot
.Lba
== 0)) {
187 SectorCount
= Catalog
->Boot
.SectorCount
;
189 switch (Catalog
->Boot
.MediaType
) {
190 case ELTORITO_NO_EMULATION
:
191 SubBlockSize
= Media
->BlockSize
;
194 case ELTORITO_HARD_DISK
:
197 case ELTORITO_12_DISKETTE
:
198 SectorCount
= 0x50 * 0x02 * 0x0F;
201 case ELTORITO_14_DISKETTE
:
202 SectorCount
= 0x50 * 0x02 * 0x12;
205 case ELTORITO_28_DISKETTE
:
206 SectorCount
= 0x50 * 0x02 * 0x24;
210 DEBUG ((DEBUG_INIT
, "EltCheckDevice: unsupported El Torito boot media type %x\n", Catalog
->Boot
.MediaType
));
212 SubBlockSize
= Media
->BlockSize
;
217 // Create child device handle
219 CdDev
.Header
.Type
= MEDIA_DEVICE_PATH
;
220 CdDev
.Header
.SubType
= MEDIA_CDROM_DP
;
221 SetDevicePathNodeLength (&CdDev
.Header
, sizeof (CdDev
));
225 // This is the initial/default entry
230 CdDev
.BootEntry
= (UINT32
)BootEntry
;
232 CdDev
.PartitionStart
= Catalog
->Boot
.Lba
* (SIZE_2KB
/ Media
->BlockSize
);
233 if (SectorCount
< 2) {
235 // When the SectorCount < 2, set the Partition as the whole CD.
237 if (VolSpaceSize
* (SIZE_2KB
/ Media
->BlockSize
) > (Media
->LastBlock
+ 1)) {
238 CdDev
.PartitionSize
= (UINT32
)(Media
->LastBlock
- Catalog
->Boot
.Lba
* (SIZE_2KB
/ Media
->BlockSize
) + 1);
240 CdDev
.PartitionSize
= (UINT32
)(VolSpaceSize
- Catalog
->Boot
.Lba
) * (SIZE_2KB
/ Media
->BlockSize
);
243 CdDev
.PartitionSize
= DivU64x32 (
245 SectorCount
* (SIZE_2KB
/ Media
->BlockSize
),
247 ) + Media
->BlockSize
- 1,
252 ZeroMem (&PartitionInfo
, sizeof (EFI_PARTITION_INFO_PROTOCOL
));
253 PartitionInfo
.Revision
= EFI_PARTITION_INFO_PROTOCOL_REVISION
;
254 PartitionInfo
.Type
= PARTITION_TYPE_OTHER
;
256 Status
= PartitionInstallChildHandle (
264 (EFI_DEVICE_PATH_PROTOCOL
*)&CdDev
,
266 Catalog
->Boot
.Lba
* (SIZE_2KB
/ Media
->BlockSize
),
267 Catalog
->Boot
.Lba
* (SIZE_2KB
/ Media
->BlockSize
) + CdDev
.PartitionSize
- 1,
271 if (!EFI_ERROR (Status
)) {
277 FreePool (VolDescriptor
);