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