]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Disk/PartitionDxe/ElTorito.c
MdeModulePkg: Apply uncrustify changes
[mirror_edk2.git] / MdeModulePkg / Universal / Disk / PartitionDxe / ElTorito.c
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 {
40 EFI_STATUS Status;
41 UINT64 VolDescriptorOffset;
42 UINT32 Lba2KB;
43 EFI_BLOCK_IO_MEDIA *Media;
44 CDROM_VOLUME_DESCRIPTOR *VolDescriptor;
45 ELTORITO_CATALOG *Catalog;
46 UINTN Check;
47 UINTN Index;
48 UINTN BootEntry;
49 UINTN MaxIndex;
50 UINT16 *CheckBuffer;
51 CDROM_DEVICE_PATH CdDev;
52 UINT32 SubBlockSize;
53 UINT32 SectorCount;
54 EFI_STATUS Found;
55 UINT32 VolSpaceSize;
56 EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
57
58 Found = EFI_NOT_FOUND;
59 Media = BlockIo->Media;
60
61 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 if (((SIZE_2KB % Media->BlockSize) != 0) || (Media->BlockSize > SIZE_2KB)) {
71 return EFI_NOT_FOUND;
72 }
73
74 VolDescriptor = AllocatePool ((UINTN)SIZE_2KB);
75
76 if (VolDescriptor == NULL) {
77 return EFI_NOT_FOUND;
78 }
79
80 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 for (VolDescriptorOffset = SIZE_32KB;
87 VolDescriptorOffset <= MultU64x32 (Media->LastBlock, Media->BlockSize);
88 VolDescriptorOffset += SIZE_2KB)
89 {
90 Status = DiskIo->ReadDisk (
91 DiskIo,
92 Media->MediaId,
93 VolDescriptorOffset,
94 SIZE_2KB,
95 VolDescriptor
96 );
97 if (EFI_ERROR (Status)) {
98 Found = Status;
99 break;
100 }
101
102 //
103 // Check for valid volume descriptor signature
104 //
105 if ((VolDescriptor->Unknown.Type == CDVOL_TYPE_END) ||
106 (CompareMem (VolDescriptor->Unknown.Id, CDVOL_ID, sizeof (VolDescriptor->Unknown.Id)) != 0)
107 )
108 {
109 //
110 // end of Volume descriptor list
111 //
112 break;
113 }
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 if (VolDescriptor->PrimaryVolume.Type == CDVOL_TYPE_CODED) {
120 VolSpaceSize = VolDescriptor->PrimaryVolume.VolSpaceSize[0];
121 }
122
123 //
124 // Is it an El Torito volume descriptor?
125 //
126 if (CompareMem (VolDescriptor->BootRecordVolume.SystemId, CDVOL_ELTORITO_ID, sizeof (CDVOL_ELTORITO_ID) - 1) != 0) {
127 continue;
128 }
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 Lba2KB = UNPACK_INT32 (VolDescriptor->BootRecordVolume.EltCatalog);
135 // Ensure the LBA (in 2KB unit) fits into our media
136 if (Lba2KB * (SIZE_2KB / Media->BlockSize) > Media->LastBlock) {
137 continue;
138 }
139
140 Status = DiskIo->ReadDisk (
141 DiskIo,
142 Media->MediaId,
143 MultU64x32 (Lba2KB, SIZE_2KB),
144 SIZE_2KB,
145 Catalog
146 );
147 if (EFI_ERROR (Status)) {
148 DEBUG ((DEBUG_ERROR, "EltCheckDevice: error reading catalog %r\n", Status));
149 continue;
150 }
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 if ((Catalog->Catalog.Indicator != ELTORITO_ID_CATALOG) || (Catalog->Catalog.Id55AA != 0xAA55)) {
157 DEBUG ((DEBUG_ERROR, "EltCheckBootCatalog: El Torito boot catalog header IDs not correct\n"));
158 continue;
159 }
160
161 Check = 0;
162 CheckBuffer = (UINT16 *)Catalog;
163 for (Index = 0; Index < sizeof (ELTORITO_CATALOG) / sizeof (UINT16); Index += 1) {
164 Check += CheckBuffer[Index];
165 }
166
167 if ((Check & 0xFFFF) != 0) {
168 DEBUG ((DEBUG_ERROR, "EltCheckBootCatalog: El Torito boot catalog header checksum failed\n"));
169 continue;
170 }
171
172 MaxIndex = Media->BlockSize / sizeof (ELTORITO_CATALOG);
173 for (Index = 1, BootEntry = 1; Index < MaxIndex; Index += 1) {
174 //
175 // Next entry
176 //
177 Catalog += 1;
178
179 //
180 // Check this entry
181 //
182 if ((Catalog->Boot.Indicator != ELTORITO_ID_SECTION_BOOTABLE) || (Catalog->Boot.Lba == 0)) {
183 continue;
184 }
185
186 SubBlockSize = 512;
187 SectorCount = Catalog->Boot.SectorCount;
188
189 switch (Catalog->Boot.MediaType) {
190 case ELTORITO_NO_EMULATION:
191 SubBlockSize = Media->BlockSize;
192 break;
193
194 case ELTORITO_HARD_DISK:
195 break;
196
197 case ELTORITO_12_DISKETTE:
198 SectorCount = 0x50 * 0x02 * 0x0F;
199 break;
200
201 case ELTORITO_14_DISKETTE:
202 SectorCount = 0x50 * 0x02 * 0x12;
203 break;
204
205 case ELTORITO_28_DISKETTE:
206 SectorCount = 0x50 * 0x02 * 0x24;
207 break;
208
209 default:
210 DEBUG ((DEBUG_INIT, "EltCheckDevice: unsupported El Torito boot media type %x\n", Catalog->Boot.MediaType));
211 SectorCount = 0;
212 SubBlockSize = Media->BlockSize;
213 break;
214 }
215
216 //
217 // Create child device handle
218 //
219 CdDev.Header.Type = MEDIA_DEVICE_PATH;
220 CdDev.Header.SubType = MEDIA_CDROM_DP;
221 SetDevicePathNodeLength (&CdDev.Header, sizeof (CdDev));
222
223 if (Index == 1) {
224 //
225 // This is the initial/default entry
226 //
227 BootEntry = 0;
228 }
229
230 CdDev.BootEntry = (UINT32)BootEntry;
231 BootEntry++;
232 CdDev.PartitionStart = Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize);
233 if (SectorCount < 2) {
234 //
235 // When the SectorCount < 2, set the Partition as the whole CD.
236 //
237 if (VolSpaceSize * (SIZE_2KB / Media->BlockSize) > (Media->LastBlock + 1)) {
238 CdDev.PartitionSize = (UINT32)(Media->LastBlock - Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize) + 1);
239 } else {
240 CdDev.PartitionSize = (UINT32)(VolSpaceSize - Catalog->Boot.Lba) * (SIZE_2KB / Media->BlockSize);
241 }
242 } else {
243 CdDev.PartitionSize = DivU64x32 (
244 MultU64x32 (
245 SectorCount * (SIZE_2KB / Media->BlockSize),
246 SubBlockSize
247 ) + Media->BlockSize - 1,
248 Media->BlockSize
249 );
250 }
251
252 ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
253 PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
254 PartitionInfo.Type = PARTITION_TYPE_OTHER;
255
256 Status = PartitionInstallChildHandle (
257 This,
258 Handle,
259 DiskIo,
260 DiskIo2,
261 BlockIo,
262 BlockIo2,
263 DevicePath,
264 (EFI_DEVICE_PATH_PROTOCOL *)&CdDev,
265 &PartitionInfo,
266 Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize),
267 Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize) + CdDev.PartitionSize - 1,
268 SubBlockSize,
269 NULL
270 );
271 if (!EFI_ERROR (Status)) {
272 Found = EFI_SUCCESS;
273 }
274 }
275 }
276
277 FreePool (VolDescriptor);
278
279 return Found;
280 }