Coverage Report

Created: 2026-04-21 06:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/Mbr.c
Line
Count
Source
1
/** @file
2
  Decode a hard disk partitioned with the legacy MBR found on most PC's
3
4
  MBR - Master Boot Record is in the first sector of a partitioned hard disk.
5
        The MBR supports four partitions per disk. The MBR also contains legacy
6
        code that is not run on an EFI system. The legacy code reads the
7
        first sector of the active partition into memory and
8
9
  BPB - BIOS Parameter Block is in the first sector of a FAT file system.
10
        The BPB contains information about the FAT file system. The BPB is
11
        always on the first sector of a media. The first sector also contains
12
        the legacy boot strap code.
13
14
Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
15
Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
16
Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
17
SPDX-License-Identifier: BSD-2-Clause-Patent
18
19
**/
20
21
#include "Partition.h"
22
23
/**
24
  Test to see if the Mbr buffer is a valid MBR.
25
26
  @param  Mbr         Parent Handle.
27
  @param  LastLba     Last Lba address on the device.
28
29
  @retval TRUE        Mbr is a Valid MBR.
30
  @retval FALSE       Mbr is not a Valid MBR.
31
32
**/
33
BOOLEAN
34
PartitionValidMbr (
35
  IN  MASTER_BOOT_RECORD  *Mbr,
36
  IN  EFI_LBA             LastLba
37
  )
38
0
{
39
0
  UINT32   StartingLBA;
40
0
  UINT32   EndingLBA;
41
0
  UINT32   NewEndingLBA;
42
0
  INTN     Index1;
43
0
  INTN     Index2;
44
0
  BOOLEAN  MbrValid;
45
46
0
  if (Mbr->Signature != MBR_SIGNATURE) {
47
0
    return FALSE;
48
0
  }
49
50
  //
51
  // The BPB also has this signature, so it can not be used alone.
52
  //
53
0
  MbrValid = FALSE;
54
0
  for (Index1 = 0; Index1 < MAX_MBR_PARTITIONS; Index1++) {
55
0
    if ((Mbr->Partition[Index1].OSIndicator == 0x00) || (UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) == 0)) {
56
0
      continue;
57
0
    }
58
59
0
    MbrValid    = TRUE;
60
0
    StartingLBA = UNPACK_UINT32 (Mbr->Partition[Index1].StartingLBA);
61
0
    EndingLBA   = StartingLBA + UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) - 1;
62
0
    if (EndingLBA > LastLba) {
63
      //
64
      // Compatibility Errata:
65
      //  Some systems try to hide drive space with their INT 13h driver
66
      //  This does not hide space from the OS driver. This means the MBR
67
      //  that gets created from DOS is smaller than the MBR created from
68
      //  a real OS (NT & Win98). This leads to BlockIo->LastBlock being
69
      //  wrong on some systems FDISKed by the OS.
70
      //
71
      // return FALSE since no block devices on a system are implemented
72
      // with INT 13h
73
      //
74
75
0
      DEBUG ((DEBUG_INFO, "PartitionValidMbr: Bad MBR partition size EndingLBA(%1x) > LastLBA(%1x)\n", EndingLBA, LastLba));
76
77
0
      return FALSE;
78
0
    }
79
80
0
    for (Index2 = Index1 + 1; Index2 < MAX_MBR_PARTITIONS; Index2++) {
81
0
      if ((Mbr->Partition[Index2].OSIndicator == 0x00) || (UNPACK_UINT32 (Mbr->Partition[Index2].SizeInLBA) == 0)) {
82
0
        continue;
83
0
      }
84
85
0
      NewEndingLBA = UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) + UNPACK_UINT32 (Mbr->Partition[Index2].SizeInLBA) - 1;
86
0
      if ((NewEndingLBA >= StartingLBA) && (UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) <= EndingLBA)) {
87
        //
88
        // This region overlaps with the Index1'th region
89
        //
90
0
        return FALSE;
91
0
      }
92
0
    }
93
0
  }
94
95
  //
96
  // None of the regions overlapped so MBR is O.K.
97
  //
98
0
  return MbrValid;
99
0
}
100
101
/**
102
  Install child handles if the Handle supports MBR format.
103
104
  @param[in]  This              Calling context.
105
  @param[in]  Handle            Parent Handle.
106
  @param[in]  DiskIo            Parent DiskIo interface.
107
  @param[in]  DiskIo2           Parent DiskIo2 interface.
108
  @param[in]  BlockIo           Parent BlockIo interface.
109
  @param[in]  BlockIo2          Parent BlockIo2 interface.
110
  @param[in]  DevicePath        Parent Device Path.
111
112
  @retval EFI_SUCCESS       A child handle was added.
113
  @retval EFI_MEDIA_CHANGED Media change was detected.
114
  @retval Others            MBR partition was not found.
115
116
**/
117
EFI_STATUS
118
PartitionInstallMbrChildHandles (
119
  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
120
  IN  EFI_HANDLE                   Handle,
121
  IN  EFI_DISK_IO_PROTOCOL         *DiskIo,
122
  IN  EFI_DISK_IO2_PROTOCOL        *DiskIo2,
123
  IN  EFI_BLOCK_IO_PROTOCOL        *BlockIo,
124
  IN  EFI_BLOCK_IO2_PROTOCOL       *BlockIo2,
125
  IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath
126
  )
127
0
{
128
0
  EFI_STATUS                   Status;
129
0
  MASTER_BOOT_RECORD           *Mbr;
130
0
  UINT32                       ExtMbrStartingLba;
131
0
  UINT32                       Index;
132
0
  HARDDRIVE_DEVICE_PATH        HdDev;
133
0
  HARDDRIVE_DEVICE_PATH        ParentHdDev;
134
0
  EFI_STATUS                   Found;
135
0
  EFI_DEVICE_PATH_PROTOCOL     *DevicePathNode;
136
0
  EFI_DEVICE_PATH_PROTOCOL     *LastDevicePathNode;
137
0
  UINT32                       BlockSize;
138
0
  UINT32                       MediaId;
139
0
  EFI_LBA                      LastSector;
140
0
  EFI_PARTITION_INFO_PROTOCOL  PartitionInfo;
141
142
0
  Found = EFI_NOT_FOUND;
143
144
0
  BlockSize  = BlockIo->Media->BlockSize;
145
0
  MediaId    = BlockIo->Media->MediaId;
146
0
  LastSector = DivU64x32 (
147
0
                 MultU64x32 (BlockIo->Media->LastBlock + 1, BlockSize),
148
0
                 MBR_SIZE
149
0
                 ) - 1;
150
151
  //
152
  // Ensure the block size can hold the MBR
153
  //
154
0
  if (BlockSize < sizeof (MASTER_BOOT_RECORD)) {
155
0
    return EFI_NOT_FOUND;
156
0
  }
157
158
0
  Mbr = AllocatePool (BlockSize);
159
0
  if (Mbr == NULL) {
160
0
    return Found;
161
0
  }
162
163
0
  Status = DiskIo->ReadDisk (
164
0
                     DiskIo,
165
0
                     MediaId,
166
0
                     0,
167
0
                     BlockSize,
168
0
                     Mbr
169
0
                     );
170
0
  if (EFI_ERROR (Status)) {
171
0
    Found = Status;
172
0
    goto Done;
173
0
  }
174
175
0
  if (!PartitionValidMbr (Mbr, LastSector)) {
176
0
    goto Done;
177
0
  }
178
179
  //
180
  // We have a valid mbr - add each partition
181
  //
182
  //
183
  // Get starting and ending LBA of the parent block device.
184
  //
185
0
  LastDevicePathNode = NULL;
186
0
  ZeroMem (&ParentHdDev, sizeof (ParentHdDev));
187
0
  DevicePathNode = DevicePath;
188
0
  while (!IsDevicePathEnd (DevicePathNode)) {
189
0
    LastDevicePathNode = DevicePathNode;
190
0
    DevicePathNode     = NextDevicePathNode (DevicePathNode);
191
0
  }
192
193
0
  if (LastDevicePathNode != NULL) {
194
0
    if ((DevicePathType (LastDevicePathNode) == MEDIA_DEVICE_PATH) &&
195
0
        (DevicePathSubType (LastDevicePathNode) == MEDIA_HARDDRIVE_DP)
196
0
        )
197
0
    {
198
0
      CopyMem (&ParentHdDev, LastDevicePathNode, sizeof (ParentHdDev));
199
0
    } else {
200
0
      LastDevicePathNode = NULL;
201
0
    }
202
0
  }
203
204
0
  ZeroMem (&HdDev, sizeof (HdDev));
205
0
  HdDev.Header.Type    = MEDIA_DEVICE_PATH;
206
0
  HdDev.Header.SubType = MEDIA_HARDDRIVE_DP;
207
0
  SetDevicePathNodeLength (&HdDev.Header, sizeof (HdDev));
208
0
  HdDev.MBRType       = MBR_TYPE_PCAT;
209
0
  HdDev.SignatureType = SIGNATURE_TYPE_MBR;
210
211
0
  if (LastDevicePathNode == NULL) {
212
    //
213
    // This is a MBR, add each partition
214
    //
215
0
    for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
216
0
      if ((Mbr->Partition[Index].OSIndicator == 0x00) || (UNPACK_UINT32 (Mbr->Partition[Index].SizeInLBA) == 0)) {
217
        //
218
        // Don't use null MBR entries
219
        //
220
0
        continue;
221
0
      }
222
223
0
      if (Mbr->Partition[Index].OSIndicator == PMBR_GPT_PARTITION) {
224
        //
225
        // This is the guard MBR for the GPT. If you ever see a GPT disk with zero partitions you can get here.
226
        //  We can not produce an MBR BlockIo for this device as the MBR spans the GPT headers. So formating
227
        //  this BlockIo would corrupt the GPT structures and require a recovery that would corrupt the format
228
        //  that corrupted the GPT partition.
229
        //
230
0
        continue;
231
0
      }
232
233
0
      HdDev.PartitionNumber = Index + 1;
234
0
      HdDev.PartitionStart  = UNPACK_UINT32 (Mbr->Partition[Index].StartingLBA);
235
0
      HdDev.PartitionSize   = UNPACK_UINT32 (Mbr->Partition[Index].SizeInLBA);
236
0
      CopyMem (HdDev.Signature, &(Mbr->UniqueMbrSignature[0]), sizeof (Mbr->UniqueMbrSignature));
237
238
0
      ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
239
0
      PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
240
0
      PartitionInfo.Type     = PARTITION_TYPE_MBR;
241
0
      if (Mbr->Partition[Index].OSIndicator == EFI_PARTITION) {
242
0
        PartitionInfo.System = 1;
243
0
      }
244
245
0
      CopyMem (&PartitionInfo.Info.Mbr, &Mbr->Partition[Index], sizeof (MBR_PARTITION_RECORD));
246
247
0
      Status = PartitionInstallChildHandle (
248
0
                 This,
249
0
                 Handle,
250
0
                 DiskIo,
251
0
                 DiskIo2,
252
0
                 BlockIo,
253
0
                 BlockIo2,
254
0
                 DevicePath,
255
0
                 (EFI_DEVICE_PATH_PROTOCOL *)&HdDev,
256
0
                 &PartitionInfo,
257
0
                 HdDev.PartitionStart,
258
0
                 HdDev.PartitionStart + HdDev.PartitionSize - 1,
259
0
                 MBR_SIZE,
260
0
                 ((Mbr->Partition[Index].OSIndicator == EFI_PARTITION) ? &gEfiPartTypeSystemPartGuid : NULL)
261
0
                 );
262
263
0
      if (!EFI_ERROR (Status)) {
264
0
        Found = EFI_SUCCESS;
265
0
      }
266
0
    }
267
0
  } else {
268
    //
269
    // It's an extended partition. Follow the extended partition
270
    // chain to get all the logical drives
271
    //
272
0
    Index             = 0;
273
0
    ExtMbrStartingLba = 0;
274
275
0
    do {
276
0
      Status = DiskIo->ReadDisk (
277
0
                         DiskIo,
278
0
                         MediaId,
279
0
                         MultU64x32 (ExtMbrStartingLba, BlockSize),
280
0
                         BlockSize,
281
0
                         Mbr
282
0
                         );
283
0
      if (EFI_ERROR (Status)) {
284
0
        Found = Status;
285
0
        goto Done;
286
0
      }
287
288
0
      if (UNPACK_UINT32 (Mbr->Partition[0].SizeInLBA) == 0) {
289
0
        break;
290
0
      }
291
292
0
      if ((Mbr->Partition[0].OSIndicator == EXTENDED_DOS_PARTITION) ||
293
0
          (Mbr->Partition[0].OSIndicator == EXTENDED_WINDOWS_PARTITION))
294
0
      {
295
0
        ExtMbrStartingLba = UNPACK_UINT32 (Mbr->Partition[0].StartingLBA);
296
        //
297
        // A value of 0 is invalid for StartingLBA
298
        //
299
0
        if (ExtMbrStartingLba == 0) {
300
0
          break;
301
0
        }
302
303
0
        continue;
304
0
      }
305
306
0
      HdDev.PartitionNumber = ++Index;
307
0
      HdDev.PartitionStart  = UNPACK_UINT32 (Mbr->Partition[0].StartingLBA) + ExtMbrStartingLba + ParentHdDev.PartitionStart;
308
0
      HdDev.PartitionSize   = UNPACK_UINT32 (Mbr->Partition[0].SizeInLBA);
309
0
      if ((HdDev.PartitionStart + HdDev.PartitionSize - 1 >= ParentHdDev.PartitionStart + ParentHdDev.PartitionSize) ||
310
0
          (HdDev.PartitionStart <= ParentHdDev.PartitionStart))
311
0
      {
312
0
        break;
313
0
      }
314
315
      //
316
      // The signature in EBR(Extended Boot Record) should always be 0.
317
      //
318
0
      *((UINT32 *)&HdDev.Signature[0]) = 0;
319
320
0
      ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
321
0
      PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
322
0
      PartitionInfo.Type     = PARTITION_TYPE_MBR;
323
0
      if (Mbr->Partition[0].OSIndicator == EFI_PARTITION) {
324
0
        PartitionInfo.System = 1;
325
0
      }
326
327
0
      CopyMem (&PartitionInfo.Info.Mbr, &Mbr->Partition[0], sizeof (MBR_PARTITION_RECORD));
328
329
0
      Status = PartitionInstallChildHandle (
330
0
                 This,
331
0
                 Handle,
332
0
                 DiskIo,
333
0
                 DiskIo2,
334
0
                 BlockIo,
335
0
                 BlockIo2,
336
0
                 DevicePath,
337
0
                 (EFI_DEVICE_PATH_PROTOCOL *)&HdDev,
338
0
                 &PartitionInfo,
339
0
                 HdDev.PartitionStart - ParentHdDev.PartitionStart,
340
0
                 HdDev.PartitionStart - ParentHdDev.PartitionStart + HdDev.PartitionSize - 1,
341
0
                 MBR_SIZE,
342
0
                 ((Mbr->Partition[0].OSIndicator == EFI_PARTITION) ? &gEfiPartTypeSystemPartGuid : NULL)
343
0
                 );
344
0
      if (!EFI_ERROR (Status)) {
345
0
        Found = EFI_SUCCESS;
346
0
      }
347
348
0
      if ((Mbr->Partition[1].OSIndicator != EXTENDED_DOS_PARTITION) &&
349
0
          (Mbr->Partition[1].OSIndicator != EXTENDED_WINDOWS_PARTITION)
350
0
          )
351
0
      {
352
0
        break;
353
0
      }
354
355
0
      ExtMbrStartingLba = UNPACK_UINT32 (Mbr->Partition[1].StartingLBA);
356
      //
357
      // Don't allow partition to be self referencing
358
      //
359
0
      if (ExtMbrStartingLba == 0) {
360
0
        break;
361
0
      }
362
0
    } while (ExtMbrStartingLba  < ParentHdDev.PartitionSize);
363
0
  }
364
365
0
Done:
366
0
  FreePool (Mbr);
367
368
0
  return Found;
369
0
}