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