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
11 #include "Partition.h"
15 Install child handles if the Handle supports El Torito format.
17 @param[in] This Calling context.
18 @param[in] Handle Parent Handle.
19 @param[in] DiskIo Parent DiskIo interface.
20 @param[in] DiskIo2 Parent DiskIo2 interface.
21 @param[in] BlockIo Parent BlockIo interface.
22 @param[in] BlockIo2 Parent BlockIo2 interface.
23 @param[in] DevicePath Parent Device Path
26 @retval EFI_SUCCESS Child handle(s) was added.
27 @retval EFI_MEDIA_CHANGED Media changed Detected.
28 @retval other no child handle was added.
32 PartitionInstallElToritoChildHandles (
33 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
35 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
36 IN EFI_DISK_IO2_PROTOCOL
*DiskIo2
,
37 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
38 IN EFI_BLOCK_IO2_PROTOCOL
*BlockIo2
,
39 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
43 UINT64 VolDescriptorOffset
;
45 EFI_BLOCK_IO_MEDIA
*Media
;
46 CDROM_VOLUME_DESCRIPTOR
*VolDescriptor
;
47 ELTORITO_CATALOG
*Catalog
;
53 CDROM_DEVICE_PATH CdDev
;
58 EFI_PARTITION_INFO_PROTOCOL PartitionInfo
;
60 Found
= EFI_NOT_FOUND
;
61 Media
= BlockIo
->Media
;
66 // CD_ROM has the fixed block size as 2048 bytes (SIZE_2KB)
69 // If the ISO image has been copied onto a different storage media
70 // then the block size might be different (eg: USB).
71 // Ensure 2048 (SIZE_2KB) is a multiple of block size
72 if (((SIZE_2KB
% Media
->BlockSize
) != 0) || (Media
->BlockSize
> SIZE_2KB
)) {
76 VolDescriptor
= AllocatePool ((UINTN
)SIZE_2KB
);
78 if (VolDescriptor
== NULL
) {
82 Catalog
= (ELTORITO_CATALOG
*) VolDescriptor
;
85 // Loop: handle one volume descriptor per time
86 // The ISO-9660 volume descriptor starts at 32k on the media
88 for (VolDescriptorOffset
= SIZE_32KB
;
89 VolDescriptorOffset
<= MultU64x32 (Media
->LastBlock
, Media
->BlockSize
);
90 VolDescriptorOffset
+= SIZE_2KB
) {
91 Status
= DiskIo
->ReadDisk (
98 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
109 // end of Volume descriptor list
114 // Read the Volume Space Size from Primary Volume Descriptor 81-88 byte,
115 // the 32-bit numerical values is stored in Both-byte orders
117 if (VolDescriptor
->PrimaryVolume
.Type
== CDVOL_TYPE_CODED
) {
118 VolSpaceSize
= VolDescriptor
->PrimaryVolume
.VolSpaceSize
[0];
121 // Is it an El Torito volume descriptor?
123 if (CompareMem (VolDescriptor
->BootRecordVolume
.SystemId
, CDVOL_ELTORITO_ID
, sizeof (CDVOL_ELTORITO_ID
) - 1) != 0) {
127 // Read in the boot El Torito boot catalog
128 // The LBA unit used by El Torito boot catalog is 2KB unit
130 Lba2KB
= UNPACK_INT32 (VolDescriptor
->BootRecordVolume
.EltCatalog
);
131 // Ensure the LBA (in 2KB unit) fits into our media
132 if (Lba2KB
* (SIZE_2KB
/ Media
->BlockSize
) > Media
->LastBlock
) {
136 Status
= DiskIo
->ReadDisk (
139 MultU64x32 (Lba2KB
, SIZE_2KB
),
143 if (EFI_ERROR (Status
)) {
144 DEBUG ((DEBUG_ERROR
, "EltCheckDevice: error reading catalog %r\n", Status
));
148 // We don't care too much about the Catalog header's contents, but we do want
149 // to make sure it looks like a Catalog header
151 if (Catalog
->Catalog
.Indicator
!= ELTORITO_ID_CATALOG
|| Catalog
->Catalog
.Id55AA
!= 0xAA55) {
152 DEBUG ((DEBUG_ERROR
, "EltCheckBootCatalog: El Torito boot catalog header IDs not correct\n"));
157 CheckBuffer
= (UINT16
*) Catalog
;
158 for (Index
= 0; Index
< sizeof (ELTORITO_CATALOG
) / sizeof (UINT16
); Index
+= 1) {
159 Check
+= CheckBuffer
[Index
];
162 if ((Check
& 0xFFFF) != 0) {
163 DEBUG ((DEBUG_ERROR
, "EltCheckBootCatalog: El Torito boot catalog header checksum failed\n"));
167 MaxIndex
= Media
->BlockSize
/ sizeof (ELTORITO_CATALOG
);
168 for (Index
= 1, BootEntry
= 1; Index
< MaxIndex
; Index
+= 1) {
177 if (Catalog
->Boot
.Indicator
!= ELTORITO_ID_SECTION_BOOTABLE
|| Catalog
->Boot
.Lba
== 0) {
182 SectorCount
= Catalog
->Boot
.SectorCount
;
184 switch (Catalog
->Boot
.MediaType
) {
186 case ELTORITO_NO_EMULATION
:
187 SubBlockSize
= Media
->BlockSize
;
190 case ELTORITO_HARD_DISK
:
193 case ELTORITO_12_DISKETTE
:
194 SectorCount
= 0x50 * 0x02 * 0x0F;
197 case ELTORITO_14_DISKETTE
:
198 SectorCount
= 0x50 * 0x02 * 0x12;
201 case ELTORITO_28_DISKETTE
:
202 SectorCount
= 0x50 * 0x02 * 0x24;
206 DEBUG ((DEBUG_INIT
, "EltCheckDevice: unsupported El Torito boot media type %x\n", Catalog
->Boot
.MediaType
));
208 SubBlockSize
= Media
->BlockSize
;
212 // Create child device handle
214 CdDev
.Header
.Type
= MEDIA_DEVICE_PATH
;
215 CdDev
.Header
.SubType
= MEDIA_CDROM_DP
;
216 SetDevicePathNodeLength (&CdDev
.Header
, sizeof (CdDev
));
220 // This is the initial/default entry
225 CdDev
.BootEntry
= (UINT32
) BootEntry
;
227 CdDev
.PartitionStart
= Catalog
->Boot
.Lba
* (SIZE_2KB
/ Media
->BlockSize
);
228 if (SectorCount
< 2) {
230 // When the SectorCount < 2, set the Partition as the whole CD.
232 if (VolSpaceSize
* (SIZE_2KB
/ Media
->BlockSize
) > (Media
->LastBlock
+ 1)) {
233 CdDev
.PartitionSize
= (UINT32
)(Media
->LastBlock
- Catalog
->Boot
.Lba
* (SIZE_2KB
/ Media
->BlockSize
) + 1);
235 CdDev
.PartitionSize
= (UINT32
)(VolSpaceSize
- Catalog
->Boot
.Lba
) * (SIZE_2KB
/ Media
->BlockSize
);
238 CdDev
.PartitionSize
= DivU64x32 (
240 SectorCount
* (SIZE_2KB
/ Media
->BlockSize
),
242 ) + Media
->BlockSize
- 1,
247 ZeroMem (&PartitionInfo
, sizeof (EFI_PARTITION_INFO_PROTOCOL
));
248 PartitionInfo
.Revision
= EFI_PARTITION_INFO_PROTOCOL_REVISION
;
249 PartitionInfo
.Type
= PARTITION_TYPE_OTHER
;
251 Status
= PartitionInstallChildHandle (
259 (EFI_DEVICE_PATH_PROTOCOL
*) &CdDev
,
261 Catalog
->Boot
.Lba
* (SIZE_2KB
/ Media
->BlockSize
),
262 Catalog
->Boot
.Lba
* (SIZE_2KB
/ Media
->BlockSize
) + CdDev
.PartitionSize
- 1,
266 if (!EFI_ERROR (Status
)) {
272 FreePool (VolDescriptor
);