2 Decode an El Torito formatted CD-ROM
4 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "Partition.h"
20 Install child handles if the Handle supports El Torito format.
22 @param[in] This Calling context.
23 @param[in] Handle Parent Handle.
24 @param[in] DiskIo Parent DiskIo interface.
25 @param[in] DiskIo2 Parent DiskIo2 interface.
26 @param[in] BlockIo Parent BlockIo interface.
27 @param[in] BlockIo2 Parent BlockIo2 interface.
28 @param[in] DevicePath Parent Device Path
31 @retval EFI_SUCCESS Child handle(s) was added.
32 @retval EFI_MEDIA_CHANGED Media changed Detected.
33 @retval other no child handle was added.
37 PartitionInstallElToritoChildHandles (
38 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
40 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
41 IN EFI_DISK_IO2_PROTOCOL
*DiskIo2
,
42 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
43 IN EFI_BLOCK_IO2_PROTOCOL
*BlockIo2
,
44 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
48 UINT64 VolDescriptorOffset
;
50 EFI_BLOCK_IO_MEDIA
*Media
;
51 CDROM_VOLUME_DESCRIPTOR
*VolDescriptor
;
52 ELTORITO_CATALOG
*Catalog
;
58 CDROM_DEVICE_PATH CdDev
;
64 Found
= EFI_NOT_FOUND
;
65 Media
= BlockIo
->Media
;
70 // CD_ROM has the fixed block size as 2048 bytes (SIZE_2KB)
73 // If the ISO image has been copied onto a different storage media
74 // then the block size might be different (eg: USB).
75 // Ensure 2048 (SIZE_2KB) is a multiple of block size
76 if (((SIZE_2KB
% Media
->BlockSize
) != 0) || (Media
->BlockSize
> SIZE_2KB
)) {
80 VolDescriptor
= AllocatePool ((UINTN
)SIZE_2KB
);
82 if (VolDescriptor
== NULL
) {
86 Catalog
= (ELTORITO_CATALOG
*) VolDescriptor
;
89 // Loop: handle one volume descriptor per time
90 // The ISO-9660 volume descriptor starts at 32k on the media
92 for (VolDescriptorOffset
= SIZE_32KB
;
93 VolDescriptorOffset
<= MultU64x32 (Media
->LastBlock
, Media
->BlockSize
);
94 VolDescriptorOffset
+= SIZE_2KB
) {
95 Status
= DiskIo
->ReadDisk (
102 if (EFI_ERROR (Status
)) {
107 // Check for valid volume descriptor signature
109 if (VolDescriptor
->Unknown
.Type
== CDVOL_TYPE_END
||
110 CompareMem (VolDescriptor
->Unknown
.Id
, CDVOL_ID
, sizeof (VolDescriptor
->Unknown
.Id
)) != 0
113 // end of Volume descriptor list
118 // Read the Volume Space Size from Primary Volume Descriptor 81-88 byte,
119 // the 32-bit numerical values is stored in Both-byte orders
121 if (VolDescriptor
->PrimaryVolume
.Type
== CDVOL_TYPE_CODED
) {
122 VolSpaceSize
= VolDescriptor
->PrimaryVolume
.VolSpaceSize
[0];
125 // Is it an El Torito volume descriptor?
127 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 ((EFI_D_ERROR
, "EltCheckDevice: error reading catalog %r\n", Status
));
152 // We don't care too much about the Catalog header's contents, but we do want
153 // to make sure it looks like a Catalog header
155 if (Catalog
->Catalog
.Indicator
!= ELTORITO_ID_CATALOG
|| Catalog
->Catalog
.Id55AA
!= 0xAA55) {
156 DEBUG ((EFI_D_ERROR
, "EltCheckBootCatalog: El Torito boot catalog header IDs not correct\n"));
161 CheckBuffer
= (UINT16
*) Catalog
;
162 for (Index
= 0; Index
< sizeof (ELTORITO_CATALOG
) / sizeof (UINT16
); Index
+= 1) {
163 Check
+= CheckBuffer
[Index
];
166 if ((Check
& 0xFFFF) != 0) {
167 DEBUG ((EFI_D_ERROR
, "EltCheckBootCatalog: El Torito boot catalog header checksum failed\n"));
171 MaxIndex
= Media
->BlockSize
/ sizeof (ELTORITO_CATALOG
);
172 for (Index
= 1, BootEntry
= 1; Index
< MaxIndex
; Index
+= 1) {
181 if (Catalog
->Boot
.Indicator
!= ELTORITO_ID_SECTION_BOOTABLE
|| Catalog
->Boot
.Lba
== 0) {
186 SectorCount
= Catalog
->Boot
.SectorCount
;
188 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 ((EFI_D_INIT
, "EltCheckDevice: unsupported El Torito boot media type %x\n", Catalog
->Boot
.MediaType
));
212 SubBlockSize
= Media
->BlockSize
;
216 // Create child device handle
218 CdDev
.Header
.Type
= MEDIA_DEVICE_PATH
;
219 CdDev
.Header
.SubType
= MEDIA_CDROM_DP
;
220 SetDevicePathNodeLength (&CdDev
.Header
, sizeof (CdDev
));
224 // This is the initial/default entry
229 CdDev
.BootEntry
= (UINT32
) BootEntry
;
231 CdDev
.PartitionStart
= Catalog
->Boot
.Lba
* (SIZE_2KB
/ Media
->BlockSize
);
232 if (SectorCount
< 2) {
234 // When the SectorCount < 2, set the Partition as the whole CD.
236 if (VolSpaceSize
* (SIZE_2KB
/ Media
->BlockSize
) > (Media
->LastBlock
+ 1)) {
237 CdDev
.PartitionSize
= (UINT32
)(Media
->LastBlock
- Catalog
->Boot
.Lba
* (SIZE_2KB
/ Media
->BlockSize
) + 1);
239 CdDev
.PartitionSize
= (UINT32
)(VolSpaceSize
- Catalog
->Boot
.Lba
) * (SIZE_2KB
/ Media
->BlockSize
);
242 CdDev
.PartitionSize
= DivU64x32 (
244 SectorCount
* (SIZE_2KB
/ Media
->BlockSize
),
246 ) + Media
->BlockSize
- 1,
251 Status
= PartitionInstallChildHandle (
259 (EFI_DEVICE_PATH_PROTOCOL
*) &CdDev
,
260 Catalog
->Boot
.Lba
* (SIZE_2KB
/ Media
->BlockSize
),
261 Catalog
->Boot
.Lba
* (SIZE_2KB
/ Media
->BlockSize
) + CdDev
.PartitionSize
- 1,
265 if (!EFI_ERROR (Status
)) {
271 FreePool (VolDescriptor
);