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