]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Disk/Partition/Dxe/ElTorito.c
added PPI and Protocol definitions needed by porting modules
[mirror_edk2.git] / MdeModulePkg / Universal / Disk / Partition / Dxe / ElTorito.c
1 /** @file
2 Decode an El Torito formatted CD-ROM
3
4 Copyright (c) 2006 - 2007, Intel Corporation
5 All rights reserved. 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 //
17 // Include common header file for this module.
18 //
19 #include "CommonHeader.h"
20
21 #include "Partition.h"
22
23
24 /**
25 Install child handles if the Handle supports El Torito format.
26
27 @param[in] This Calling context.
28 @param[in] Handle Parent Handle
29 @param[in] DiskIo Parent DiskIo interface
30 @param[in] BlockIo Parent BlockIo interface
31 @param[in] DevicePath Parent Device Path
32
33
34 @retval EFI_SUCCESS Child handle(s) was added
35 @retval EFI_MEDIA_CHANGED Media changed Detected
36 @retval other no child handle was added
37
38 **/
39 EFI_STATUS
40 PartitionInstallElToritoChildHandles (
41 IN EFI_DRIVER_BINDING_PROTOCOL *This,
42 IN EFI_HANDLE Handle,
43 IN EFI_DISK_IO_PROTOCOL *DiskIo,
44 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
45 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
46 )
47 {
48 EFI_STATUS Status;
49 UINT32 VolDescriptorLba;
50 UINT32 Lba;
51 EFI_BLOCK_IO_MEDIA *Media;
52 CDROM_VOLUME_DESCRIPTOR *VolDescriptor;
53 ELTORITO_CATALOG *Catalog;
54 UINTN Check;
55 UINTN Index;
56 UINTN BootEntry;
57 UINTN MaxIndex;
58 UINT16 *CheckBuffer;
59 CDROM_DEVICE_PATH CdDev;
60 UINT32 SubBlockSize;
61 UINT32 SectorCount;
62 EFI_STATUS Found;
63 UINT32 VolSpaceSize;
64
65 Found = EFI_NOT_FOUND;
66 Media = BlockIo->Media;
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 = BlockIo->ReadBlocks (
106 BlockIo,
107 Media->MediaId,
108 VolDescriptorLba,
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->Type == CDVOL_TYPE_END ||
120 CompareMem (VolDescriptor->Id, CDVOL_ID, sizeof (VolDescriptor->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->Type == CDVOL_TYPE_CODED) {
132 VolSpaceSize = VolDescriptor->VolSpaceSize[0];
133 }
134 //
135 // Is it an El Torito volume descriptor?
136 //
137 if (CompareMem (VolDescriptor->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->EltCatalog);
144 if (Lba > Media->LastBlock) {
145 continue;
146 }
147
148 Status = BlockIo->ReadBlocks (
149 BlockIo,
150 Media->MediaId,
151 Lba,
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) {
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 BlockIo,
264 DevicePath,
265 (EFI_DEVICE_PATH_PROTOCOL *) &CdDev,
266 Catalog->Boot.Lba,
267 Catalog->Boot.Lba + CdDev.PartitionSize - 1,
268 SubBlockSize,
269 FALSE
270 );
271 if (!EFI_ERROR (Status)) {
272 Found = EFI_SUCCESS;
273 }
274 }
275 }
276
277 FreePool (VolDescriptor);
278
279 return Found;
280 }