13b94c307fc0201bc5a4da66e062c1da6e6975ba
[mirror_edk2.git] / MdeModulePkg / Universal / Disk / PartitionDxe / ElTorito.c
1 /** @file
2 Decode an El Torito formatted CD-ROM
3
4 Copyright (c) 2006 - 2011, 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] BlockIo Parent BlockIo interface.
26 @param[in] BlockIo2 Parent BlockIo2 interface.
27 @param[in] DevicePath Parent Device Path
28
29
30 @retval EFI_SUCCESS Child handle(s) was added.
31 @retval EFI_MEDIA_CHANGED Media changed Detected.
32 @retval other no child handle was added.
33
34 **/
35 EFI_STATUS
36 PartitionInstallElToritoChildHandles (
37 IN EFI_DRIVER_BINDING_PROTOCOL *This,
38 IN EFI_HANDLE Handle,
39 IN EFI_DISK_IO_PROTOCOL *DiskIo,
40 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
41 IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
42 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
43 )
44 {
45 EFI_STATUS Status;
46 UINT32 VolDescriptorLba;
47 UINT32 Lba;
48 EFI_BLOCK_IO_MEDIA *Media;
49 CDROM_VOLUME_DESCRIPTOR *VolDescriptor;
50 ELTORITO_CATALOG *Catalog;
51 UINTN Check;
52 UINTN Index;
53 UINTN BootEntry;
54 UINTN MaxIndex;
55 UINT16 *CheckBuffer;
56 CDROM_DEVICE_PATH CdDev;
57 UINT32 SubBlockSize;
58 UINT32 SectorCount;
59 EFI_STATUS Found;
60 UINT32 VolSpaceSize;
61
62 Found = EFI_NOT_FOUND;
63 Media = BlockIo->Media;
64
65 VolSpaceSize = 0;
66
67 //
68 // CD_ROM has the fixed block size as 2048 bytes
69 //
70 if (Media->BlockSize != 2048) {
71 return EFI_NOT_FOUND;
72 }
73
74 VolDescriptor = AllocatePool ((UINTN) Media->BlockSize);
75
76 if (VolDescriptor == NULL) {
77 return EFI_NOT_FOUND;
78 }
79
80 Catalog = (ELTORITO_CATALOG *) VolDescriptor;
81
82 //
83 // the ISO-9660 volume descriptor starts at 32k on the media
84 // and CD_ROM has the fixed block size as 2048 bytes, so...
85 //
86 //
87 // ((16*2048) / Media->BlockSize) - 1;
88 //
89 VolDescriptorLba = 15;
90 //
91 // Loop: handle one volume descriptor per time
92 //
93 while (TRUE) {
94
95 VolDescriptorLba += 1;
96 if (VolDescriptorLba > Media->LastBlock) {
97 //
98 // We are pointing past the end of the device so exit
99 //
100 break;
101 }
102
103 Status = DiskIo->ReadDisk (
104 DiskIo,
105 Media->MediaId,
106 MultU64x32 (VolDescriptorLba, Media->BlockSize),
107 Media->BlockSize,
108 VolDescriptor
109 );
110 if (EFI_ERROR (Status)) {
111 Found = Status;
112 break;
113 }
114 //
115 // Check for valid volume descriptor signature
116 //
117 if (VolDescriptor->Unknown.Type == CDVOL_TYPE_END ||
118 CompareMem (VolDescriptor->Unknown.Id, CDVOL_ID, sizeof (VolDescriptor->Unknown.Id)) != 0
119 ) {
120 //
121 // end of Volume descriptor list
122 //
123 break;
124 }
125 //
126 // Read the Volume Space Size from Primary Volume Descriptor 81-88 byte,
127 // the 32-bit numerical values is stored in Both-byte orders
128 //
129 if (VolDescriptor->PrimaryVolume.Type == CDVOL_TYPE_CODED) {
130 VolSpaceSize = VolDescriptor->PrimaryVolume.VolSpaceSize[0];
131 }
132 //
133 // Is it an El Torito volume descriptor?
134 //
135 if (CompareMem (VolDescriptor->BootRecordVolume.SystemId, CDVOL_ELTORITO_ID, sizeof (CDVOL_ELTORITO_ID) - 1) != 0) {
136 continue;
137 }
138 //
139 // Read in the boot El Torito boot catalog
140 //
141 Lba = UNPACK_INT32 (VolDescriptor->BootRecordVolume.EltCatalog);
142 if (Lba > Media->LastBlock) {
143 continue;
144 }
145
146 Status = DiskIo->ReadDisk (
147 DiskIo,
148 Media->MediaId,
149 MultU64x32 (Lba, Media->BlockSize),
150 Media->BlockSize,
151 Catalog
152 );
153 if (EFI_ERROR (Status)) {
154 DEBUG ((EFI_D_ERROR, "EltCheckDevice: error reading catalog %r\n", Status));
155 continue;
156 }
157 //
158 // We don't care too much about the Catalog header's contents, but we do want
159 // to make sure it looks like a Catalog header
160 //
161 if (Catalog->Catalog.Indicator != ELTORITO_ID_CATALOG || Catalog->Catalog.Id55AA != 0xAA55) {
162 DEBUG ((EFI_D_ERROR, "EltCheckBootCatalog: El Torito boot catalog header IDs not correct\n"));
163 continue;
164 }
165
166 Check = 0;
167 CheckBuffer = (UINT16 *) Catalog;
168 for (Index = 0; Index < sizeof (ELTORITO_CATALOG) / sizeof (UINT16); Index += 1) {
169 Check += CheckBuffer[Index];
170 }
171
172 if ((Check & 0xFFFF) != 0) {
173 DEBUG ((EFI_D_ERROR, "EltCheckBootCatalog: El Torito boot catalog header checksum failed\n"));
174 continue;
175 }
176
177 MaxIndex = Media->BlockSize / sizeof (ELTORITO_CATALOG);
178 for (Index = 1, BootEntry = 1; Index < MaxIndex; Index += 1) {
179 //
180 // Next entry
181 //
182 Catalog += 1;
183
184 //
185 // Check this entry
186 //
187 if (Catalog->Boot.Indicator != ELTORITO_ID_SECTION_BOOTABLE || Catalog->Boot.Lba == 0) {
188 continue;
189 }
190
191 SubBlockSize = 512;
192 SectorCount = Catalog->Boot.SectorCount;
193
194 switch (Catalog->Boot.MediaType) {
195
196 case ELTORITO_NO_EMULATION:
197 SubBlockSize = Media->BlockSize;
198 break;
199
200 case ELTORITO_HARD_DISK:
201 break;
202
203 case ELTORITO_12_DISKETTE:
204 SectorCount = 0x50 * 0x02 * 0x0F;
205 break;
206
207 case ELTORITO_14_DISKETTE:
208 SectorCount = 0x50 * 0x02 * 0x12;
209 break;
210
211 case ELTORITO_28_DISKETTE:
212 SectorCount = 0x50 * 0x02 * 0x24;
213 break;
214
215 default:
216 DEBUG ((EFI_D_INIT, "EltCheckDevice: unsupported El Torito boot media type %x\n", Catalog->Boot.MediaType));
217 SectorCount = 0;
218 SubBlockSize = Media->BlockSize;
219 break;
220 }
221 //
222 // Create child device handle
223 //
224 CdDev.Header.Type = MEDIA_DEVICE_PATH;
225 CdDev.Header.SubType = MEDIA_CDROM_DP;
226 SetDevicePathNodeLength (&CdDev.Header, sizeof (CdDev));
227
228 if (Index == 1) {
229 //
230 // This is the initial/default entry
231 //
232 BootEntry = 0;
233 }
234
235 CdDev.BootEntry = (UINT32) BootEntry;
236 BootEntry++;
237 CdDev.PartitionStart = Catalog->Boot.Lba;
238 if (SectorCount < 2) {
239 //
240 // When the SectorCount < 2, set the Partition as the whole CD.
241 //
242 if (VolSpaceSize > (Media->LastBlock + 1)) {
243 CdDev.PartitionSize = (UINT32)(Media->LastBlock - Catalog->Boot.Lba + 1);
244 } else {
245 CdDev.PartitionSize = (UINT32)(VolSpaceSize - Catalog->Boot.Lba);
246 }
247 } else {
248 CdDev.PartitionSize = DivU64x32 (
249 MultU64x32 (
250 SectorCount,
251 SubBlockSize
252 ) + Media->BlockSize - 1,
253 Media->BlockSize
254 );
255 }
256
257 Status = PartitionInstallChildHandle (
258 This,
259 Handle,
260 DiskIo,
261 BlockIo,
262 BlockIo2,
263 DevicePath,
264 (EFI_DEVICE_PATH_PROTOCOL *) &CdDev,
265 Catalog->Boot.Lba,
266 Catalog->Boot.Lba + CdDev.PartitionSize - 1,
267 SubBlockSize,
268 FALSE
269 );
270 if (!EFI_ERROR (Status)) {
271 Found = EFI_SUCCESS;
272 }
273 }
274 }
275
276 FreePool (VolDescriptor);
277
278 return Found;
279 }