]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Disk/PartitionDxe/ElTorito.c
MdeModulePkg/PartitionDxe: Add impl of Partition Information Protocol
[mirror_edk2.git] / MdeModulePkg / Universal / Disk / PartitionDxe / ElTorito.c
1 /** @file
2 Decode an El Torito formatted CD-ROM
3
4 Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
5 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 #include "Partition.h"
17
18
19 /**
20 Install child handles if the Handle supports El Torito format.
21
22 @param[in] This Calling context.
23 @param[in] Handle Parent Handle.
24 @param[in] DiskIo Parent DiskIo interface.
25 @param[in] DiskIo2 Parent DiskIo2 interface.
26 @param[in] BlockIo Parent BlockIo interface.
27 @param[in] BlockIo2 Parent BlockIo2 interface.
28 @param[in] DevicePath Parent Device Path
29
30
31 @retval EFI_SUCCESS Child handle(s) was added.
32 @retval EFI_MEDIA_CHANGED Media changed Detected.
33 @retval other no child handle was added.
34
35 **/
36 EFI_STATUS
37 PartitionInstallElToritoChildHandles (
38 IN EFI_DRIVER_BINDING_PROTOCOL *This,
39 IN EFI_HANDLE Handle,
40 IN EFI_DISK_IO_PROTOCOL *DiskIo,
41 IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
42 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
43 IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
44 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
45 )
46 {
47 EFI_STATUS Status;
48 UINT64 VolDescriptorOffset;
49 UINT32 Lba2KB;
50 EFI_BLOCK_IO_MEDIA *Media;
51 CDROM_VOLUME_DESCRIPTOR *VolDescriptor;
52 ELTORITO_CATALOG *Catalog;
53 UINTN Check;
54 UINTN Index;
55 UINTN BootEntry;
56 UINTN MaxIndex;
57 UINT16 *CheckBuffer;
58 CDROM_DEVICE_PATH CdDev;
59 UINT32 SubBlockSize;
60 UINT32 SectorCount;
61 EFI_STATUS Found;
62 UINT32 VolSpaceSize;
63 EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
64
65 Found = EFI_NOT_FOUND;
66 Media = BlockIo->Media;
67
68 VolSpaceSize = 0;
69
70 //
71 // CD_ROM has the fixed block size as 2048 bytes (SIZE_2KB)
72 //
73
74 // If the ISO image has been copied onto a different storage media
75 // then the block size might be different (eg: USB).
76 // Ensure 2048 (SIZE_2KB) is a multiple of block size
77 if (((SIZE_2KB % Media->BlockSize) != 0) || (Media->BlockSize > SIZE_2KB)) {
78 return EFI_NOT_FOUND;
79 }
80
81 VolDescriptor = AllocatePool ((UINTN)SIZE_2KB);
82
83 if (VolDescriptor == NULL) {
84 return EFI_NOT_FOUND;
85 }
86
87 Catalog = (ELTORITO_CATALOG *) VolDescriptor;
88
89 //
90 // Loop: handle one volume descriptor per time
91 // The ISO-9660 volume descriptor starts at 32k on the media
92 //
93 for (VolDescriptorOffset = SIZE_32KB;
94 VolDescriptorOffset <= MultU64x32 (Media->LastBlock, Media->BlockSize);
95 VolDescriptorOffset += SIZE_2KB) {
96 Status = DiskIo->ReadDisk (
97 DiskIo,
98 Media->MediaId,
99 VolDescriptorOffset,
100 SIZE_2KB,
101 VolDescriptor
102 );
103 if (EFI_ERROR (Status)) {
104 Found = Status;
105 break;
106 }
107 //
108 // Check for valid volume descriptor signature
109 //
110 if (VolDescriptor->Unknown.Type == CDVOL_TYPE_END ||
111 CompareMem (VolDescriptor->Unknown.Id, CDVOL_ID, sizeof (VolDescriptor->Unknown.Id)) != 0
112 ) {
113 //
114 // end of Volume descriptor list
115 //
116 break;
117 }
118 //
119 // Read the Volume Space Size from Primary Volume Descriptor 81-88 byte,
120 // the 32-bit numerical values is stored in Both-byte orders
121 //
122 if (VolDescriptor->PrimaryVolume.Type == CDVOL_TYPE_CODED) {
123 VolSpaceSize = VolDescriptor->PrimaryVolume.VolSpaceSize[0];
124 }
125 //
126 // Is it an El Torito volume descriptor?
127 //
128 if (CompareMem (VolDescriptor->BootRecordVolume.SystemId, CDVOL_ELTORITO_ID, sizeof (CDVOL_ELTORITO_ID) - 1) != 0) {
129 continue;
130 }
131 //
132 // Read in the boot El Torito boot catalog
133 // The LBA unit used by El Torito boot catalog is 2KB unit
134 //
135 Lba2KB = UNPACK_INT32 (VolDescriptor->BootRecordVolume.EltCatalog);
136 // Ensure the LBA (in 2KB unit) fits into our media
137 if (Lba2KB * (SIZE_2KB / Media->BlockSize) > Media->LastBlock) {
138 continue;
139 }
140
141 Status = DiskIo->ReadDisk (
142 DiskIo,
143 Media->MediaId,
144 MultU64x32 (Lba2KB, SIZE_2KB),
145 SIZE_2KB,
146 Catalog
147 );
148 if (EFI_ERROR (Status)) {
149 DEBUG ((EFI_D_ERROR, "EltCheckDevice: error reading catalog %r\n", Status));
150 continue;
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 ((EFI_D_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 ((EFI_D_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
191 case ELTORITO_NO_EMULATION:
192 SubBlockSize = Media->BlockSize;
193 break;
194
195 case ELTORITO_HARD_DISK:
196 break;
197
198 case ELTORITO_12_DISKETTE:
199 SectorCount = 0x50 * 0x02 * 0x0F;
200 break;
201
202 case ELTORITO_14_DISKETTE:
203 SectorCount = 0x50 * 0x02 * 0x12;
204 break;
205
206 case ELTORITO_28_DISKETTE:
207 SectorCount = 0x50 * 0x02 * 0x24;
208 break;
209
210 default:
211 DEBUG ((EFI_D_INIT, "EltCheckDevice: unsupported El Torito boot media type %x\n", Catalog->Boot.MediaType));
212 SectorCount = 0;
213 SubBlockSize = Media->BlockSize;
214 break;
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 );
270 if (!EFI_ERROR (Status)) {
271 Found = EFI_SUCCESS;
272 }
273 }
274 }
275
276 FreePool (VolDescriptor);
277
278 return Found;
279 }