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