1 /** @file
2 Decode an El Torito formatted CD-ROM
3
4 Copyright (c) 2006 - 2015, 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
9
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.
12
13 **/
14
15
16 #include "Partition.h"
17
18
19 /**
20 Install child handles if the Handle supports El Torito format.
21
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
29
30
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.
34
35 **/
36 EFI_STATUS
PartitionInstallElToritoChildHandles(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Handle,IN EFI_DISK_IO_PROTOCOL * DiskIo,IN EFI_DISK_IO2_PROTOCOL * DiskIo2,IN EFI_BLOCK_IO_PROTOCOL * BlockIo,IN EFI_BLOCK_IO2_PROTOCOL * BlockIo2,IN EFI_DEVICE_PATH_PROTOCOL * DevicePath)37 PartitionInstallElToritoChildHandles (
38 IN EFI_DRIVER_BINDING_PROTOCOL *This,
39 IN EFI_HANDLE Handle,
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
45 )
46 {
47 EFI_STATUS Status;
48 UINT64 VolDescriptorOffset;
49 UINT32 Lba2KB;
50 EFI_BLOCK_IO_MEDIA *Media;
51 CDROM_VOLUME_DESCRIPTOR *VolDescriptor;
52 ELTORITO_CATALOG *Catalog;
53 UINTN Check;
54 UINTN Index;
55 UINTN BootEntry;
56 UINTN MaxIndex;
57 UINT16 *CheckBuffer;
58 CDROM_DEVICE_PATH CdDev;
59 UINT32 SubBlockSize;
60 UINT32 SectorCount;
61 EFI_STATUS Found;
62 UINT32 VolSpaceSize;
63
64 Found = EFI_NOT_FOUND;
65 Media = BlockIo->Media;
66
67 VolSpaceSize = 0;
68
69 //
70 // CD_ROM has the fixed block size as 2048 bytes (SIZE_2KB)
71 //
72
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)) {
77 return EFI_NOT_FOUND;
78 }
79
80 VolDescriptor = AllocatePool ((UINTN)SIZE_2KB);
81
82 if (VolDescriptor == NULL) {
83 return EFI_NOT_FOUND;
84 }
85
86 Catalog = (ELTORITO_CATALOG *) VolDescriptor;
87
88 //
89 // Loop: handle one volume descriptor per time
90 // The ISO-9660 volume descriptor starts at 32k on the media
91 //
92 for (VolDescriptorOffset = SIZE_32KB;
93 VolDescriptorOffset <= MultU64x32 (Media->LastBlock, Media->BlockSize);
94 VolDescriptorOffset += SIZE_2KB) {
95 Status = DiskIo->ReadDisk (
96 DiskIo,
97 Media->MediaId,
98 VolDescriptorOffset,
99 SIZE_2KB,
100 VolDescriptor
101 );
102 if (EFI_ERROR (Status)) {
103 Found = Status;
104 break;
105 }
106 //
107 // Check for valid volume descriptor signature
108 //
109 if (VolDescriptor->Unknown.Type == CDVOL_TYPE_END ||
110 CompareMem (VolDescriptor->Unknown.Id, CDVOL_ID, sizeof (VolDescriptor->Unknown.Id)) != 0
111 ) {
112 //
113 // end of Volume descriptor list
114 //
115 break;
116 }
117 //
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
120 //
121 if (VolDescriptor->PrimaryVolume.Type == CDVOL_TYPE_CODED) {
122 VolSpaceSize = VolDescriptor->PrimaryVolume.VolSpaceSize[0];
123 }
124 //
125 // Is it an El Torito volume descriptor?
126 //
127 if (CompareMem (VolDescriptor->BootRecordVolume.SystemId, CDVOL_ELTORITO_ID, sizeof (CDVOL_ELTORITO_ID) - 1) != 0) {
128 continue;
129 }
130 //
131 // Read in the boot El Torito boot catalog
132 // The LBA unit used by El Torito boot catalog is 2KB unit
133 //
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) {
137 continue;
138 }
139
140 Status = DiskIo->ReadDisk (
141 DiskIo,
142 Media->MediaId,
143 MultU64x32 (Lba2KB, SIZE_2KB),
144 SIZE_2KB,
145 Catalog
146 );
147 if (EFI_ERROR (Status)) {
148 DEBUG ((EFI_D_ERROR, "EltCheckDevice: error reading catalog %r\n", Status));
149 continue;
150 }
151 //
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
154 //
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"));
157 continue;
158 }
159
160 Check = 0;
161 CheckBuffer = (UINT16 *) Catalog;
162 for (Index = 0; Index < sizeof (ELTORITO_CATALOG) / sizeof (UINT16); Index += 1) {
163 Check += CheckBuffer[Index];
164 }
165
166 if ((Check & 0xFFFF) != 0) {
167 DEBUG ((EFI_D_ERROR, "EltCheckBootCatalog: El Torito boot catalog header checksum failed\n"));
168 continue;
169 }
170
171 MaxIndex = Media->BlockSize / sizeof (ELTORITO_CATALOG);
172 for (Index = 1, BootEntry = 1; Index < MaxIndex; Index += 1) {
173 //
174 // Next entry
175 //
176 Catalog += 1;
177
178 //
179 // Check this entry
180 //
181 if (Catalog->Boot.Indicator != ELTORITO_ID_SECTION_BOOTABLE || Catalog->Boot.Lba == 0) {
182 continue;
183 }
184
185 SubBlockSize = 512;
186 SectorCount = Catalog->Boot.SectorCount * (SIZE_2KB / Media->BlockSize);
187
188 switch (Catalog->Boot.MediaType) {
189
190 case ELTORITO_NO_EMULATION:
191 SubBlockSize = Media->BlockSize;
192 break;
193
194 case ELTORITO_HARD_DISK:
195 break;
196
197 case ELTORITO_12_DISKETTE:
198 SectorCount = 0x50 * 0x02 * 0x0F;
199 break;
200
201 case ELTORITO_14_DISKETTE:
202 SectorCount = 0x50 * 0x02 * 0x12;
203 break;
204
205 case ELTORITO_28_DISKETTE:
206 SectorCount = 0x50 * 0x02 * 0x24;
207 break;
208
209 default:
210 DEBUG ((EFI_D_INIT, "EltCheckDevice: unsupported El Torito boot media type %x\n", Catalog->Boot.MediaType));
211 SectorCount = 0;
212 SubBlockSize = Media->BlockSize;
213 break;
214 }
215 //
216 // Create child device handle
217 //
218 CdDev.Header.Type = MEDIA_DEVICE_PATH;
219 CdDev.Header.SubType = MEDIA_CDROM_DP;
220 SetDevicePathNodeLength (&CdDev.Header, sizeof (CdDev));
221
222 if (Index == 1) {
223 //
224 // This is the initial/default entry
225 //
226 BootEntry = 0;
227 }
228
229 CdDev.BootEntry = (UINT32) BootEntry;
230 BootEntry++;
231 CdDev.PartitionStart = Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize);
232 if (SectorCount < 2) {
233 //
234 // When the SectorCount < 2, set the Partition as the whole CD.
235 //
236 if (VolSpaceSize > (Media->LastBlock + 1)) {
237 CdDev.PartitionSize = (UINT32)(Media->LastBlock - Catalog->Boot.Lba + 1);
238 } else {
239 CdDev.PartitionSize = (UINT32)(VolSpaceSize - Catalog->Boot.Lba);
240 }
241 } else {
242 CdDev.PartitionSize = DivU64x32 (
243 MultU64x32 (
244 SectorCount,
245 SubBlockSize
246 ) + Media->BlockSize - 1,
247 Media->BlockSize
248 );
249 }
250
251 Status = PartitionInstallChildHandle (
252 This,
253 Handle,
254 DiskIo,
255 DiskIo2,
256 BlockIo,
257 BlockIo2,
258 DevicePath,
259 (EFI_DEVICE_PATH_PROTOCOL *) &CdDev,
260 Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize),
261 MultU64x32 (Catalog->Boot.Lba + CdDev.PartitionSize - 1, SIZE_2KB / Media->BlockSize),
262 SubBlockSize,
263 FALSE
264 );
265 if (!EFI_ERROR (Status)) {
266 Found = EFI_SUCCESS;
267 }
268 }
269 }
270
271 FreePool (VolDescriptor);
272
273 return Found;
274 }
275