Coverage Report

Created: 2025-12-05 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}