/src/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/ElTorito.c
Line | Count | Source |
1 | | /** @file |
2 | | Decode an El Torito formatted CD-ROM |
3 | | |
4 | | Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc. |
5 | | Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR> |
6 | | SPDX-License-Identifier: BSD-2-Clause-Patent |
7 | | |
8 | | **/ |
9 | | |
10 | | #include "Partition.h" |
11 | | |
12 | | /** |
13 | | Install child handles if the Handle supports El Torito format. |
14 | | |
15 | | @param[in] This Calling context. |
16 | | @param[in] Handle Parent Handle. |
17 | | @param[in] DiskIo Parent DiskIo interface. |
18 | | @param[in] DiskIo2 Parent DiskIo2 interface. |
19 | | @param[in] BlockIo Parent BlockIo interface. |
20 | | @param[in] BlockIo2 Parent BlockIo2 interface. |
21 | | @param[in] DevicePath Parent Device Path |
22 | | |
23 | | |
24 | | @retval EFI_SUCCESS Child handle(s) was added. |
25 | | @retval EFI_MEDIA_CHANGED Media changed Detected. |
26 | | @retval other no child handle was added. |
27 | | |
28 | | **/ |
29 | | EFI_STATUS |
30 | | PartitionInstallElToritoChildHandles ( |
31 | | IN EFI_DRIVER_BINDING_PROTOCOL *This, |
32 | | IN EFI_HANDLE Handle, |
33 | | IN EFI_DISK_IO_PROTOCOL *DiskIo, |
34 | | IN EFI_DISK_IO2_PROTOCOL *DiskIo2, |
35 | | IN EFI_BLOCK_IO_PROTOCOL *BlockIo, |
36 | | IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2, |
37 | | IN EFI_DEVICE_PATH_PROTOCOL *DevicePath |
38 | | ) |
39 | 0 | { |
40 | 0 | EFI_STATUS Status; |
41 | 0 | UINT64 VolDescriptorOffset; |
42 | 0 | UINT32 Lba2KB; |
43 | 0 | EFI_BLOCK_IO_MEDIA *Media; |
44 | 0 | CDROM_VOLUME_DESCRIPTOR *VolDescriptor; |
45 | 0 | ELTORITO_CATALOG *Catalog; |
46 | 0 | UINTN Check; |
47 | 0 | UINTN Index; |
48 | 0 | UINTN BootEntry; |
49 | 0 | UINTN MaxIndex; |
50 | 0 | UINT16 *CheckBuffer; |
51 | 0 | CDROM_DEVICE_PATH CdDev; |
52 | 0 | UINT32 SubBlockSize; |
53 | 0 | UINT32 SectorCount; |
54 | 0 | EFI_STATUS Found; |
55 | 0 | UINT32 VolSpaceSize; |
56 | 0 | EFI_PARTITION_INFO_PROTOCOL PartitionInfo; |
57 | |
|
58 | 0 | Found = EFI_NOT_FOUND; |
59 | 0 | Media = BlockIo->Media; |
60 | |
|
61 | 0 | VolSpaceSize = 0; |
62 | | |
63 | | // |
64 | | // CD_ROM has the fixed block size as 2048 bytes (SIZE_2KB) |
65 | | // |
66 | | |
67 | | // If the ISO image has been copied onto a different storage media |
68 | | // then the block size might be different (eg: USB). |
69 | | // Ensure 2048 (SIZE_2KB) is a multiple of block size |
70 | 0 | if (((SIZE_2KB % Media->BlockSize) != 0) || (Media->BlockSize > SIZE_2KB)) { |
71 | 0 | return EFI_NOT_FOUND; |
72 | 0 | } |
73 | | |
74 | 0 | VolDescriptor = AllocatePool ((UINTN)SIZE_2KB); |
75 | |
|
76 | 0 | if (VolDescriptor == NULL) { |
77 | 0 | return EFI_NOT_FOUND; |
78 | 0 | } |
79 | | |
80 | 0 | Catalog = (ELTORITO_CATALOG *)VolDescriptor; |
81 | | |
82 | | // |
83 | | // Loop: handle one volume descriptor per time |
84 | | // The ISO-9660 volume descriptor starts at 32k on the media |
85 | | // |
86 | 0 | for (VolDescriptorOffset = SIZE_32KB; |
87 | 0 | VolDescriptorOffset <= MultU64x32 (Media->LastBlock, Media->BlockSize); |
88 | 0 | VolDescriptorOffset += SIZE_2KB) |
89 | 0 | { |
90 | 0 | Status = DiskIo->ReadDisk ( |
91 | 0 | DiskIo, |
92 | 0 | Media->MediaId, |
93 | 0 | VolDescriptorOffset, |
94 | 0 | SIZE_2KB, |
95 | 0 | VolDescriptor |
96 | 0 | ); |
97 | 0 | if (EFI_ERROR (Status)) { |
98 | 0 | Found = Status; |
99 | 0 | break; |
100 | 0 | } |
101 | | |
102 | | // |
103 | | // Check for valid volume descriptor signature |
104 | | // |
105 | 0 | if ((VolDescriptor->Unknown.Type == CDVOL_TYPE_END) || |
106 | 0 | (CompareMem (VolDescriptor->Unknown.Id, CDVOL_ID, sizeof (VolDescriptor->Unknown.Id)) != 0) |
107 | 0 | ) |
108 | 0 | { |
109 | | // |
110 | | // end of Volume descriptor list |
111 | | // |
112 | 0 | break; |
113 | 0 | } |
114 | | |
115 | | // |
116 | | // Read the Volume Space Size from Primary Volume Descriptor 81-88 byte, |
117 | | // the 32-bit numerical values is stored in Both-byte orders |
118 | | // |
119 | 0 | if (VolDescriptor->PrimaryVolume.Type == CDVOL_TYPE_CODED) { |
120 | 0 | VolSpaceSize = VolDescriptor->PrimaryVolume.VolSpaceSize[0]; |
121 | 0 | } |
122 | | |
123 | | // |
124 | | // Is it an El Torito volume descriptor? |
125 | | // |
126 | 0 | if (CompareMem (VolDescriptor->BootRecordVolume.SystemId, CDVOL_ELTORITO_ID, sizeof (CDVOL_ELTORITO_ID) - 1) != 0) { |
127 | 0 | continue; |
128 | 0 | } |
129 | | |
130 | | // |
131 | | // Read in the boot El Torito boot catalog |
132 | | // The LBA unit used by El Torito boot catalog is 2KB unit |
133 | | // |
134 | 0 | Lba2KB = UNPACK_INT32 (VolDescriptor->BootRecordVolume.EltCatalog); |
135 | | // Ensure the LBA (in 2KB unit) fits into our media |
136 | 0 | if (Lba2KB * (SIZE_2KB / Media->BlockSize) > Media->LastBlock) { |
137 | 0 | continue; |
138 | 0 | } |
139 | | |
140 | 0 | Status = DiskIo->ReadDisk ( |
141 | 0 | DiskIo, |
142 | 0 | Media->MediaId, |
143 | 0 | MultU64x32 (Lba2KB, SIZE_2KB), |
144 | 0 | SIZE_2KB, |
145 | 0 | Catalog |
146 | 0 | ); |
147 | 0 | if (EFI_ERROR (Status)) { |
148 | 0 | DEBUG ((DEBUG_ERROR, "EltCheckDevice: error reading catalog %r\n", Status)); |
149 | 0 | continue; |
150 | 0 | } |
151 | | |
152 | | // |
153 | | // We don't care too much about the Catalog header's contents, but we do want |
154 | | // to make sure it looks like a Catalog header |
155 | | // |
156 | 0 | if ((Catalog->Catalog.Indicator != ELTORITO_ID_CATALOG) || (Catalog->Catalog.Id55AA != 0xAA55)) { |
157 | 0 | DEBUG ((DEBUG_ERROR, "EltCheckBootCatalog: El Torito boot catalog header IDs not correct\n")); |
158 | 0 | continue; |
159 | 0 | } |
160 | | |
161 | 0 | Check = 0; |
162 | 0 | CheckBuffer = (UINT16 *)Catalog; |
163 | 0 | for (Index = 0; Index < sizeof (ELTORITO_CATALOG) / sizeof (UINT16); Index += 1) { |
164 | 0 | Check += CheckBuffer[Index]; |
165 | 0 | } |
166 | |
|
167 | 0 | if ((Check & 0xFFFF) != 0) { |
168 | 0 | DEBUG ((DEBUG_ERROR, "EltCheckBootCatalog: El Torito boot catalog header checksum failed\n")); |
169 | 0 | continue; |
170 | 0 | } |
171 | | |
172 | 0 | MaxIndex = Media->BlockSize / sizeof (ELTORITO_CATALOG); |
173 | 0 | for (Index = 1, BootEntry = 1; Index < MaxIndex; Index += 1) { |
174 | | // |
175 | | // Next entry |
176 | | // |
177 | 0 | Catalog += 1; |
178 | | |
179 | | // |
180 | | // Check this entry |
181 | | // |
182 | 0 | if ((Catalog->Boot.Indicator != ELTORITO_ID_SECTION_BOOTABLE) || (Catalog->Boot.Lba == 0)) { |
183 | 0 | continue; |
184 | 0 | } |
185 | | |
186 | 0 | SubBlockSize = 512; |
187 | 0 | SectorCount = Catalog->Boot.SectorCount; |
188 | |
|
189 | 0 | switch (Catalog->Boot.MediaType) { |
190 | 0 | case ELTORITO_NO_EMULATION: |
191 | 0 | SubBlockSize = Media->BlockSize; |
192 | 0 | break; |
193 | | |
194 | 0 | case ELTORITO_HARD_DISK: |
195 | 0 | break; |
196 | | |
197 | 0 | case ELTORITO_12_DISKETTE: |
198 | 0 | SectorCount = 0x50 * 0x02 * 0x0F; |
199 | 0 | break; |
200 | | |
201 | 0 | case ELTORITO_14_DISKETTE: |
202 | 0 | SectorCount = 0x50 * 0x02 * 0x12; |
203 | 0 | break; |
204 | | |
205 | 0 | case ELTORITO_28_DISKETTE: |
206 | 0 | SectorCount = 0x50 * 0x02 * 0x24; |
207 | 0 | break; |
208 | | |
209 | 0 | default: |
210 | 0 | DEBUG ((DEBUG_INIT, "EltCheckDevice: unsupported El Torito boot media type %x\n", Catalog->Boot.MediaType)); |
211 | 0 | SectorCount = 0; |
212 | 0 | SubBlockSize = Media->BlockSize; |
213 | 0 | break; |
214 | 0 | } |
215 | | |
216 | | // |
217 | | // Create child device handle |
218 | | // |
219 | 0 | CdDev.Header.Type = MEDIA_DEVICE_PATH; |
220 | 0 | CdDev.Header.SubType = MEDIA_CDROM_DP; |
221 | 0 | SetDevicePathNodeLength (&CdDev.Header, sizeof (CdDev)); |
222 | |
|
223 | 0 | if (Index == 1) { |
224 | | // |
225 | | // This is the initial/default entry |
226 | | // |
227 | 0 | BootEntry = 0; |
228 | 0 | } |
229 | |
|
230 | 0 | CdDev.BootEntry = (UINT32)BootEntry; |
231 | 0 | BootEntry++; |
232 | 0 | CdDev.PartitionStart = Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize); |
233 | 0 | if (SectorCount < 2) { |
234 | | // |
235 | | // When the SectorCount < 2, set the Partition as the whole CD. |
236 | | // |
237 | 0 | if (VolSpaceSize * (SIZE_2KB / Media->BlockSize) > (Media->LastBlock + 1)) { |
238 | 0 | CdDev.PartitionSize = (UINT32)(Media->LastBlock - Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize) + 1); |
239 | 0 | } else { |
240 | 0 | CdDev.PartitionSize = (UINT32)(VolSpaceSize - Catalog->Boot.Lba) * (SIZE_2KB / Media->BlockSize); |
241 | 0 | } |
242 | 0 | } else { |
243 | 0 | CdDev.PartitionSize = DivU64x32 ( |
244 | 0 | MultU64x32 ( |
245 | 0 | SectorCount * (SIZE_2KB / Media->BlockSize), |
246 | 0 | SubBlockSize |
247 | 0 | ) + Media->BlockSize - 1, |
248 | 0 | Media->BlockSize |
249 | 0 | ); |
250 | 0 | } |
251 | |
|
252 | 0 | ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL)); |
253 | 0 | PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION; |
254 | 0 | PartitionInfo.Type = PARTITION_TYPE_OTHER; |
255 | |
|
256 | 0 | Status = PartitionInstallChildHandle ( |
257 | 0 | This, |
258 | 0 | Handle, |
259 | 0 | DiskIo, |
260 | 0 | DiskIo2, |
261 | 0 | BlockIo, |
262 | 0 | BlockIo2, |
263 | 0 | DevicePath, |
264 | 0 | (EFI_DEVICE_PATH_PROTOCOL *)&CdDev, |
265 | 0 | &PartitionInfo, |
266 | 0 | Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize), |
267 | 0 | Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize) + CdDev.PartitionSize - 1, |
268 | 0 | SubBlockSize, |
269 | 0 | NULL |
270 | 0 | ); |
271 | 0 | if (!EFI_ERROR (Status)) { |
272 | 0 | Found = EFI_SUCCESS; |
273 | 0 | } |
274 | 0 | } |
275 | 0 | } |
276 | | |
277 | 0 | FreePool (VolDescriptor); |
278 | |
|
279 | 0 | return Found; |
280 | 0 | } |