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 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this 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,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include "Partition.h"
21 Install child handles if the Handle supports El Torito format.
23 @param[in] This Calling context.
24 @param[in] Handle Parent Handle.
25 @param[in] DiskIo Parent DiskIo interface.
26 @param[in] DiskIo2 Parent DiskIo2 interface.
27 @param[in] BlockIo Parent BlockIo interface.
28 @param[in] BlockIo2 Parent BlockIo2 interface.
29 @param[in] DevicePath Parent Device Path
32 @retval EFI_SUCCESS Child handle(s) was added.
33 @retval EFI_MEDIA_CHANGED Media changed Detected.
34 @retval other no child handle was added.
38 PartitionInstallElToritoChildHandles (
39 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
41 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
42 IN EFI_DISK_IO2_PROTOCOL
*DiskIo2
,
43 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
44 IN EFI_BLOCK_IO2_PROTOCOL
*BlockIo2
,
45 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
49 UINT64 VolDescriptorOffset
;
51 EFI_BLOCK_IO_MEDIA
*Media
;
52 CDROM_VOLUME_DESCRIPTOR
*VolDescriptor
;
53 ELTORITO_CATALOG
*Catalog
;
59 CDROM_DEVICE_PATH CdDev
;
64 EFI_PARTITION_INFO_PROTOCOL PartitionInfo
;
66 Found
= EFI_NOT_FOUND
;
67 Media
= BlockIo
->Media
;
72 // CD_ROM has the fixed block size as 2048 bytes (SIZE_2KB)
75 // If the ISO image has been copied onto a different storage media
76 // then the block size might be different (eg: USB).
77 // Ensure 2048 (SIZE_2KB) is a multiple of block size
78 if (((SIZE_2KB
% Media
->BlockSize
) != 0) || (Media
->BlockSize
> SIZE_2KB
)) {
82 VolDescriptor
= AllocatePool ((UINTN
)SIZE_2KB
);
84 if (VolDescriptor
== NULL
) {
88 Catalog
= (ELTORITO_CATALOG
*) VolDescriptor
;
91 // Loop: handle one volume descriptor per time
92 // The ISO-9660 volume descriptor starts at 32k on the media
94 for (VolDescriptorOffset
= SIZE_32KB
;
95 VolDescriptorOffset
<= MultU64x32 (Media
->LastBlock
, Media
->BlockSize
);
96 VolDescriptorOffset
+= SIZE_2KB
) {
97 Status
= DiskIo
->ReadDisk (
104 if (EFI_ERROR (Status
)) {
109 // Check for valid volume descriptor signature
111 if (VolDescriptor
->Unknown
.Type
== CDVOL_TYPE_END
||
112 CompareMem (VolDescriptor
->Unknown
.Id
, CDVOL_ID
, sizeof (VolDescriptor
->Unknown
.Id
)) != 0
115 // end of Volume descriptor list
120 // Read the Volume Space Size from Primary Volume Descriptor 81-88 byte,
121 // the 32-bit numerical values is stored in Both-byte orders
123 if (VolDescriptor
->PrimaryVolume
.Type
== CDVOL_TYPE_CODED
) {
124 VolSpaceSize
= VolDescriptor
->PrimaryVolume
.VolSpaceSize
[0];
127 // Is it an El Torito volume descriptor?
129 if (CompareMem (VolDescriptor
->BootRecordVolume
.SystemId
, CDVOL_ELTORITO_ID
, sizeof (CDVOL_ELTORITO_ID
) - 1) != 0) {
133 // Read in the boot El Torito boot catalog
134 // The LBA unit used by El Torito boot catalog is 2KB unit
136 Lba2KB
= UNPACK_INT32 (VolDescriptor
->BootRecordVolume
.EltCatalog
);
137 // Ensure the LBA (in 2KB unit) fits into our media
138 if (Lba2KB
* (SIZE_2KB
/ Media
->BlockSize
) > Media
->LastBlock
) {
142 Status
= DiskIo
->ReadDisk (
145 MultU64x32 (Lba2KB
, SIZE_2KB
),
149 if (EFI_ERROR (Status
)) {
150 DEBUG ((EFI_D_ERROR
, "EltCheckDevice: error reading catalog %r\n", Status
));
154 // We don't care too much about the Catalog header's contents, but we do want
155 // to make sure it looks like a Catalog header
157 if (Catalog
->Catalog
.Indicator
!= ELTORITO_ID_CATALOG
|| Catalog
->Catalog
.Id55AA
!= 0xAA55) {
158 DEBUG ((EFI_D_ERROR
, "EltCheckBootCatalog: El Torito boot catalog header IDs not correct\n"));
163 CheckBuffer
= (UINT16
*) Catalog
;
164 for (Index
= 0; Index
< sizeof (ELTORITO_CATALOG
) / sizeof (UINT16
); Index
+= 1) {
165 Check
+= CheckBuffer
[Index
];
168 if ((Check
& 0xFFFF) != 0) {
169 DEBUG ((EFI_D_ERROR
, "EltCheckBootCatalog: El Torito boot catalog header checksum failed\n"));
173 MaxIndex
= Media
->BlockSize
/ sizeof (ELTORITO_CATALOG
);
174 for (Index
= 1, BootEntry
= 1; Index
< MaxIndex
; Index
+= 1) {
183 if (Catalog
->Boot
.Indicator
!= ELTORITO_ID_SECTION_BOOTABLE
|| Catalog
->Boot
.Lba
== 0) {
188 SectorCount
= Catalog
->Boot
.SectorCount
;
190 switch (Catalog
->Boot
.MediaType
) {
192 case ELTORITO_NO_EMULATION
:
193 SubBlockSize
= Media
->BlockSize
;
196 case ELTORITO_HARD_DISK
:
199 case ELTORITO_12_DISKETTE
:
200 SectorCount
= 0x50 * 0x02 * 0x0F;
203 case ELTORITO_14_DISKETTE
:
204 SectorCount
= 0x50 * 0x02 * 0x12;
207 case ELTORITO_28_DISKETTE
:
208 SectorCount
= 0x50 * 0x02 * 0x24;
212 DEBUG ((EFI_D_INIT
, "EltCheckDevice: unsupported El Torito boot media type %x\n", Catalog
->Boot
.MediaType
));
214 SubBlockSize
= Media
->BlockSize
;
218 // Create child device handle
220 CdDev
.Header
.Type
= MEDIA_DEVICE_PATH
;
221 CdDev
.Header
.SubType
= MEDIA_CDROM_DP
;
222 SetDevicePathNodeLength (&CdDev
.Header
, sizeof (CdDev
));
226 // This is the initial/default entry
231 CdDev
.BootEntry
= (UINT32
) BootEntry
;
233 CdDev
.PartitionStart
= Catalog
->Boot
.Lba
* (SIZE_2KB
/ Media
->BlockSize
);
234 if (SectorCount
< 2) {
236 // When the SectorCount < 2, set the Partition as the whole CD.
238 if (VolSpaceSize
* (SIZE_2KB
/ Media
->BlockSize
) > (Media
->LastBlock
+ 1)) {
239 CdDev
.PartitionSize
= (UINT32
)(Media
->LastBlock
- Catalog
->Boot
.Lba
* (SIZE_2KB
/ Media
->BlockSize
) + 1);
241 CdDev
.PartitionSize
= (UINT32
)(VolSpaceSize
- Catalog
->Boot
.Lba
) * (SIZE_2KB
/ Media
->BlockSize
);
244 CdDev
.PartitionSize
= DivU64x32 (
246 SectorCount
* (SIZE_2KB
/ Media
->BlockSize
),
248 ) + Media
->BlockSize
- 1,
253 ZeroMem (&PartitionInfo
, sizeof (EFI_PARTITION_INFO_PROTOCOL
));
254 PartitionInfo
.Revision
= EFI_PARTITION_INFO_PROTOCOL_REVISION
;
255 PartitionInfo
.Type
= PARTITION_TYPE_OTHER
;
257 Status
= PartitionInstallChildHandle (
265 (EFI_DEVICE_PATH_PROTOCOL
*) &CdDev
,
267 Catalog
->Boot
.Lba
* (SIZE_2KB
/ Media
->BlockSize
),
268 Catalog
->Boot
.Lba
* (SIZE_2KB
/ Media
->BlockSize
) + CdDev
.PartitionSize
- 1,
272 if (!EFI_ERROR (Status
)) {
278 FreePool (VolDescriptor
);