1 | /* $Id: ElTorito.c 48730 2013-09-27 12:28:22Z vboxsync $ */
|
---|
2 | /** @file
|
---|
3 | * ElTorito.c
|
---|
4 | */
|
---|
5 |
|
---|
6 | /*
|
---|
7 | * Copyright (C) 2012 Oracle Corporation
|
---|
8 | *
|
---|
9 | * This file is part of VirtualBox Open Source Edition (OSE), as
|
---|
10 | * available from http://www.virtualbox.org. This file is free software;
|
---|
11 | * you can redistribute it and/or modify it under the terms of the GNU
|
---|
12 | * General Public License (GPL) as published by the Free Software
|
---|
13 | * Foundation, in version 2 as it comes in the "COPYING" file of the
|
---|
14 | * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
|
---|
15 | * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
|
---|
16 | *
|
---|
17 | * The contents of this file may alternatively be used under the terms
|
---|
18 | * of the Common Development and Distribution License Version 1.0
|
---|
19 | * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
|
---|
20 | * VirtualBox OSE distribution, in which case the provisions of the
|
---|
21 | * CDDL are applicable instead of those of the GPL.
|
---|
22 | *
|
---|
23 | * You may elect to license modified versions of this file under the
|
---|
24 | * terms and conditions of either the GPL or the CDDL or both.
|
---|
25 | */
|
---|
26 |
|
---|
27 | /** @file
|
---|
28 | Decode an El Torito formatted CD-ROM
|
---|
29 |
|
---|
30 | Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
|
---|
31 | This program and the accompanying materials
|
---|
32 | are licensed and made available under the terms and conditions of the BSD License
|
---|
33 | which accompanies this distribution. The full text of the license may be found at
|
---|
34 | http://opensource.org/licenses/bsd-license.php
|
---|
35 |
|
---|
36 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
---|
37 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
---|
38 |
|
---|
39 | **/
|
---|
40 |
|
---|
41 |
|
---|
42 | #include "Partition.h"
|
---|
43 |
|
---|
44 |
|
---|
45 | /**
|
---|
46 | Install child handles if the Handle supports El Torito format.
|
---|
47 |
|
---|
48 | @param[in] This Calling context.
|
---|
49 | @param[in] Handle Parent Handle.
|
---|
50 | @param[in] DiskIo Parent DiskIo interface.
|
---|
51 | @param[in] BlockIo Parent BlockIo interface.
|
---|
52 | @param[in] BlockIo2 Parent BlockIo2 interface.
|
---|
53 | @param[in] DevicePath Parent Device Path
|
---|
54 |
|
---|
55 |
|
---|
56 | @retval EFI_SUCCESS Child handle(s) was added.
|
---|
57 | @retval EFI_MEDIA_CHANGED Media changed Detected.
|
---|
58 | @retval other no child handle was added.
|
---|
59 |
|
---|
60 | **/
|
---|
61 | EFI_STATUS
|
---|
62 | PartitionInstallElToritoChildHandles (
|
---|
63 | IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
---|
64 | IN EFI_HANDLE Handle,
|
---|
65 | IN EFI_DISK_IO_PROTOCOL *DiskIo,
|
---|
66 | IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
|
---|
67 | IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
|
---|
68 | IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
|
---|
69 | )
|
---|
70 | {
|
---|
71 | EFI_STATUS Status;
|
---|
72 | UINT32 VolDescriptorLba;
|
---|
73 | UINT32 Lba;
|
---|
74 | EFI_BLOCK_IO_MEDIA *Media;
|
---|
75 | CDROM_VOLUME_DESCRIPTOR *VolDescriptor;
|
---|
76 | ELTORITO_CATALOG *Catalog;
|
---|
77 | UINTN Check;
|
---|
78 | UINTN Index;
|
---|
79 | UINTN BootEntry;
|
---|
80 | UINTN MaxIndex;
|
---|
81 | UINT16 *CheckBuffer;
|
---|
82 | CDROM_DEVICE_PATH CdDev;
|
---|
83 | UINT32 SubBlockSize;
|
---|
84 | UINT32 SectorCount;
|
---|
85 | EFI_STATUS Found;
|
---|
86 | UINT32 VolSpaceSize;
|
---|
87 |
|
---|
88 | VBoxLogFlowFuncMarkDP(DevicePath);
|
---|
89 | Found = EFI_NOT_FOUND;
|
---|
90 | Media = BlockIo->Media;
|
---|
91 |
|
---|
92 | VolSpaceSize = 0;
|
---|
93 |
|
---|
94 | //
|
---|
95 | // CD_ROM has the fixed block size as 2048 bytes
|
---|
96 | //
|
---|
97 | if (Media->BlockSize != 2048) {
|
---|
98 | return EFI_NOT_FOUND;
|
---|
99 | }
|
---|
100 |
|
---|
101 | VolDescriptor = AllocatePool ((UINTN) Media->BlockSize);
|
---|
102 |
|
---|
103 | if (VolDescriptor == NULL) {
|
---|
104 | return EFI_NOT_FOUND;
|
---|
105 | }
|
---|
106 |
|
---|
107 | Catalog = (ELTORITO_CATALOG *) VolDescriptor;
|
---|
108 |
|
---|
109 | //
|
---|
110 | // the ISO-9660 volume descriptor starts at 32k on the media
|
---|
111 | // and CD_ROM has the fixed block size as 2048 bytes, so...
|
---|
112 | //
|
---|
113 | //
|
---|
114 | // ((16*2048) / Media->BlockSize) - 1;
|
---|
115 | //
|
---|
116 | VolDescriptorLba = 15;
|
---|
117 | //
|
---|
118 | // Loop: handle one volume descriptor per time
|
---|
119 | //
|
---|
120 | while (TRUE) {
|
---|
121 |
|
---|
122 | VolDescriptorLba += 1;
|
---|
123 | if (VolDescriptorLba > Media->LastBlock) {
|
---|
124 | //
|
---|
125 | // We are pointing past the end of the device so exit
|
---|
126 | //
|
---|
127 | break;
|
---|
128 | }
|
---|
129 |
|
---|
130 | Status = DiskIo->ReadDisk (
|
---|
131 | DiskIo,
|
---|
132 | Media->MediaId,
|
---|
133 | MultU64x32 (VolDescriptorLba, Media->BlockSize),
|
---|
134 | Media->BlockSize,
|
---|
135 | VolDescriptor
|
---|
136 | );
|
---|
137 | if (EFI_ERROR (Status)) {
|
---|
138 | Found = Status;
|
---|
139 | break;
|
---|
140 | }
|
---|
141 | //
|
---|
142 | // Check for valid volume descriptor signature
|
---|
143 | //
|
---|
144 | if (VolDescriptor->Unknown.Type == CDVOL_TYPE_END ||
|
---|
145 | CompareMem (VolDescriptor->Unknown.Id, CDVOL_ID, sizeof (VolDescriptor->Unknown.Id)) != 0
|
---|
146 | ) {
|
---|
147 | //
|
---|
148 | // end of Volume descriptor list
|
---|
149 | //
|
---|
150 | break;
|
---|
151 | }
|
---|
152 | //
|
---|
153 | // Read the Volume Space Size from Primary Volume Descriptor 81-88 byte,
|
---|
154 | // the 32-bit numerical values is stored in Both-byte orders
|
---|
155 | //
|
---|
156 | if (VolDescriptor->PrimaryVolume.Type == CDVOL_TYPE_CODED) {
|
---|
157 | VolSpaceSize = VolDescriptor->PrimaryVolume.VolSpaceSize[0];
|
---|
158 | }
|
---|
159 | //
|
---|
160 | // Is it an El Torito volume descriptor?
|
---|
161 | //
|
---|
162 | if (CompareMem (VolDescriptor->BootRecordVolume.SystemId, CDVOL_ELTORITO_ID, sizeof (CDVOL_ELTORITO_ID) - 1) != 0) {
|
---|
163 | continue;
|
---|
164 | }
|
---|
165 | //
|
---|
166 | // Read in the boot El Torito boot catalog
|
---|
167 | //
|
---|
168 | Lba = UNPACK_INT32 (VolDescriptor->BootRecordVolume.EltCatalog);
|
---|
169 | if (Lba > Media->LastBlock) {
|
---|
170 | continue;
|
---|
171 | }
|
---|
172 |
|
---|
173 | Status = DiskIo->ReadDisk (
|
---|
174 | DiskIo,
|
---|
175 | Media->MediaId,
|
---|
176 | MultU64x32 (Lba, Media->BlockSize),
|
---|
177 | Media->BlockSize,
|
---|
178 | Catalog
|
---|
179 | );
|
---|
180 | if (EFI_ERROR (Status)) {
|
---|
181 | DEBUG ((EFI_D_ERROR, "EltCheckDevice: error reading catalog %r\n", Status));
|
---|
182 | continue;
|
---|
183 | }
|
---|
184 | //
|
---|
185 | // We don't care too much about the Catalog header's contents, but we do want
|
---|
186 | // to make sure it looks like a Catalog header
|
---|
187 | //
|
---|
188 | if (Catalog->Catalog.Indicator != ELTORITO_ID_CATALOG || Catalog->Catalog.Id55AA != 0xAA55) {
|
---|
189 | DEBUG ((EFI_D_ERROR, "EltCheckBootCatalog: El Torito boot catalog header IDs not correct\n"));
|
---|
190 | continue;
|
---|
191 | }
|
---|
192 |
|
---|
193 | Check = 0;
|
---|
194 | CheckBuffer = (UINT16 *) Catalog;
|
---|
195 | for (Index = 0; Index < sizeof (ELTORITO_CATALOG) / sizeof (UINT16); Index += 1) {
|
---|
196 | Check += CheckBuffer[Index];
|
---|
197 | }
|
---|
198 |
|
---|
199 | if ((Check & 0xFFFF) != 0) {
|
---|
200 | DEBUG ((EFI_D_ERROR, "EltCheckBootCatalog: El Torito boot catalog header checksum failed\n"));
|
---|
201 | continue;
|
---|
202 | }
|
---|
203 |
|
---|
204 | MaxIndex = Media->BlockSize / sizeof (ELTORITO_CATALOG);
|
---|
205 | for (Index = 1, BootEntry = 1; Index < MaxIndex; Index += 1) {
|
---|
206 | //
|
---|
207 | // Next entry
|
---|
208 | //
|
---|
209 | Catalog += 1;
|
---|
210 |
|
---|
211 | //
|
---|
212 | // Check this entry
|
---|
213 | //
|
---|
214 | if (Catalog->Boot.Indicator != ELTORITO_ID_SECTION_BOOTABLE || Catalog->Boot.Lba == 0) {
|
---|
215 | continue;
|
---|
216 | }
|
---|
217 |
|
---|
218 | SubBlockSize = 512;
|
---|
219 | SectorCount = Catalog->Boot.SectorCount;
|
---|
220 |
|
---|
221 | switch (Catalog->Boot.MediaType) {
|
---|
222 |
|
---|
223 | case ELTORITO_NO_EMULATION:
|
---|
224 | SubBlockSize = Media->BlockSize;
|
---|
225 | break;
|
---|
226 |
|
---|
227 | case ELTORITO_HARD_DISK:
|
---|
228 | break;
|
---|
229 |
|
---|
230 | case ELTORITO_12_DISKETTE:
|
---|
231 | SectorCount = 0x50 * 0x02 * 0x0F;
|
---|
232 | break;
|
---|
233 |
|
---|
234 | case ELTORITO_14_DISKETTE:
|
---|
235 | SectorCount = 0x50 * 0x02 * 0x12;
|
---|
236 | break;
|
---|
237 |
|
---|
238 | case ELTORITO_28_DISKETTE:
|
---|
239 | SectorCount = 0x50 * 0x02 * 0x24;
|
---|
240 | break;
|
---|
241 |
|
---|
242 | default:
|
---|
243 | DEBUG ((EFI_D_INIT, "EltCheckDevice: unsupported El Torito boot media type %x\n", Catalog->Boot.MediaType));
|
---|
244 | SectorCount = 0;
|
---|
245 | SubBlockSize = Media->BlockSize;
|
---|
246 | break;
|
---|
247 | }
|
---|
248 | //
|
---|
249 | // Create child device handle
|
---|
250 | //
|
---|
251 | CdDev.Header.Type = MEDIA_DEVICE_PATH;
|
---|
252 | CdDev.Header.SubType = MEDIA_CDROM_DP;
|
---|
253 | SetDevicePathNodeLength (&CdDev.Header, sizeof (CdDev));
|
---|
254 |
|
---|
255 | if (Index == 1) {
|
---|
256 | //
|
---|
257 | // This is the initial/default entry
|
---|
258 | //
|
---|
259 | BootEntry = 0;
|
---|
260 | }
|
---|
261 |
|
---|
262 | CdDev.BootEntry = (UINT32) BootEntry;
|
---|
263 | BootEntry++;
|
---|
264 | CdDev.PartitionStart = Catalog->Boot.Lba;
|
---|
265 | if (SectorCount < 2) {
|
---|
266 | //
|
---|
267 | // When the SectorCount < 2, set the Partition as the whole CD.
|
---|
268 | //
|
---|
269 | if (VolSpaceSize > (Media->LastBlock + 1)) {
|
---|
270 | CdDev.PartitionSize = (UINT32)(Media->LastBlock - Catalog->Boot.Lba + 1);
|
---|
271 | } else {
|
---|
272 | CdDev.PartitionSize = (UINT32)(VolSpaceSize - Catalog->Boot.Lba);
|
---|
273 | }
|
---|
274 | } else {
|
---|
275 | CdDev.PartitionSize = DivU64x32 (
|
---|
276 | MultU64x32 (
|
---|
277 | SectorCount,
|
---|
278 | SubBlockSize
|
---|
279 | ) + Media->BlockSize - 1,
|
---|
280 | Media->BlockSize
|
---|
281 | );
|
---|
282 | }
|
---|
283 |
|
---|
284 | Status = PartitionInstallChildHandle (
|
---|
285 | This,
|
---|
286 | Handle,
|
---|
287 | DiskIo,
|
---|
288 | BlockIo,
|
---|
289 | BlockIo2,
|
---|
290 | DevicePath,
|
---|
291 | (EFI_DEVICE_PATH_PROTOCOL *) &CdDev,
|
---|
292 | Catalog->Boot.Lba,
|
---|
293 | Catalog->Boot.Lba + CdDev.PartitionSize - 1,
|
---|
294 | SubBlockSize,
|
---|
295 | FALSE
|
---|
296 | );
|
---|
297 | if (!EFI_ERROR (Status)) {
|
---|
298 | Found = EFI_SUCCESS;
|
---|
299 | }
|
---|
300 | }
|
---|
301 | }
|
---|
302 |
|
---|
303 | FreePool (VolDescriptor);
|
---|
304 |
|
---|
305 | return Found;
|
---|
306 | }
|
---|