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