2 Decode a hard disk partitioned with the legacy MBR found on most PC's
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
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.
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
21 #include "Partition.h"
24 Test to see if the Mbr buffer is a valid MBR.
26 @param Mbr Parent Handle.
27 @param LastLba Last Lba address on the device.
29 @retval TRUE Mbr is a Valid MBR.
30 @retval FALSE Mbr is not a Valid MBR.
35 IN MASTER_BOOT_RECORD
*Mbr
,
46 if (Mbr
->Signature
!= MBR_SIGNATURE
) {
51 // The BPB also has this signature, so it can not be used alone.
54 for (Index1
= 0; Index1
< MAX_MBR_PARTITIONS
; Index1
++) {
55 if ((Mbr
->Partition
[Index1
].OSIndicator
== 0x00) || (UNPACK_UINT32 (Mbr
->Partition
[Index1
].SizeInLBA
) == 0)) {
60 StartingLBA
= UNPACK_UINT32 (Mbr
->Partition
[Index1
].StartingLBA
);
61 EndingLBA
= StartingLBA
+ UNPACK_UINT32 (Mbr
->Partition
[Index1
].SizeInLBA
) - 1;
62 if (EndingLBA
> LastLba
) {
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.
71 // return FALSE since no block devices on a system are implemented
75 DEBUG ((DEBUG_INFO
, "PartitionValidMbr: Bad MBR partition size EndingLBA(%1x) > LastLBA(%1x)\n", EndingLBA
, LastLba
));
80 for (Index2
= Index1
+ 1; Index2
< MAX_MBR_PARTITIONS
; Index2
++) {
81 if ((Mbr
->Partition
[Index2
].OSIndicator
== 0x00) || (UNPACK_UINT32 (Mbr
->Partition
[Index2
].SizeInLBA
) == 0)) {
85 NewEndingLBA
= UNPACK_UINT32 (Mbr
->Partition
[Index2
].StartingLBA
) + UNPACK_UINT32 (Mbr
->Partition
[Index2
].SizeInLBA
) - 1;
86 if ((NewEndingLBA
>= StartingLBA
) && (UNPACK_UINT32 (Mbr
->Partition
[Index2
].StartingLBA
) <= EndingLBA
)) {
88 // This region overlaps with the Index1'th region
96 // None of the regions overlapped so MBR is O.K.
102 Install child handles if the Handle supports MBR format.
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.
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.
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
129 MASTER_BOOT_RECORD
*Mbr
;
130 UINT32 ExtMbrStartingLba
;
132 HARDDRIVE_DEVICE_PATH HdDev
;
133 HARDDRIVE_DEVICE_PATH ParentHdDev
;
135 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
136 EFI_DEVICE_PATH_PROTOCOL
*LastDevicePathNode
;
140 EFI_PARTITION_INFO_PROTOCOL PartitionInfo
;
142 Found
= EFI_NOT_FOUND
;
144 BlockSize
= BlockIo
->Media
->BlockSize
;
145 MediaId
= BlockIo
->Media
->MediaId
;
146 LastSector
= DivU64x32 (
147 MultU64x32 (BlockIo
->Media
->LastBlock
+ 1, BlockSize
),
152 // Ensure the block size can hold the MBR
154 if (BlockSize
< sizeof (MASTER_BOOT_RECORD
)) {
155 return EFI_NOT_FOUND
;
158 Mbr
= AllocatePool (BlockSize
);
163 Status
= DiskIo
->ReadDisk (
170 if (EFI_ERROR (Status
)) {
175 if (!PartitionValidMbr (Mbr
, LastSector
)) {
180 // We have a valid mbr - add each partition
183 // Get starting and ending LBA of the parent block device.
185 LastDevicePathNode
= NULL
;
186 ZeroMem (&ParentHdDev
, sizeof (ParentHdDev
));
187 DevicePathNode
= DevicePath
;
188 while (!IsDevicePathEnd (DevicePathNode
)) {
189 LastDevicePathNode
= DevicePathNode
;
190 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
193 if (LastDevicePathNode
!= NULL
) {
194 if ((DevicePathType (LastDevicePathNode
) == MEDIA_DEVICE_PATH
) &&
195 (DevicePathSubType (LastDevicePathNode
) == MEDIA_HARDDRIVE_DP
)
198 CopyMem (&ParentHdDev
, LastDevicePathNode
, sizeof (ParentHdDev
));
200 LastDevicePathNode
= NULL
;
204 ZeroMem (&HdDev
, sizeof (HdDev
));
205 HdDev
.Header
.Type
= MEDIA_DEVICE_PATH
;
206 HdDev
.Header
.SubType
= MEDIA_HARDDRIVE_DP
;
207 SetDevicePathNodeLength (&HdDev
.Header
, sizeof (HdDev
));
208 HdDev
.MBRType
= MBR_TYPE_PCAT
;
209 HdDev
.SignatureType
= SIGNATURE_TYPE_MBR
;
211 if (LastDevicePathNode
== NULL
) {
213 // This is a MBR, add each partition
215 for (Index
= 0; Index
< MAX_MBR_PARTITIONS
; Index
++) {
216 if ((Mbr
->Partition
[Index
].OSIndicator
== 0x00) || (UNPACK_UINT32 (Mbr
->Partition
[Index
].SizeInLBA
) == 0)) {
218 // Don't use null MBR entries
223 if (Mbr
->Partition
[Index
].OSIndicator
== PMBR_GPT_PARTITION
) {
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.
233 HdDev
.PartitionNumber
= Index
+ 1;
234 HdDev
.PartitionStart
= UNPACK_UINT32 (Mbr
->Partition
[Index
].StartingLBA
);
235 HdDev
.PartitionSize
= UNPACK_UINT32 (Mbr
->Partition
[Index
].SizeInLBA
);
236 CopyMem (HdDev
.Signature
, &(Mbr
->UniqueMbrSignature
[0]), sizeof (Mbr
->UniqueMbrSignature
));
238 ZeroMem (&PartitionInfo
, sizeof (EFI_PARTITION_INFO_PROTOCOL
));
239 PartitionInfo
.Revision
= EFI_PARTITION_INFO_PROTOCOL_REVISION
;
240 PartitionInfo
.Type
= PARTITION_TYPE_MBR
;
241 if (Mbr
->Partition
[Index
].OSIndicator
== EFI_PARTITION
) {
242 PartitionInfo
.System
= 1;
245 CopyMem (&PartitionInfo
.Info
.Mbr
, &Mbr
->Partition
[Index
], sizeof (MBR_PARTITION_RECORD
));
247 Status
= PartitionInstallChildHandle (
255 (EFI_DEVICE_PATH_PROTOCOL
*)&HdDev
,
257 HdDev
.PartitionStart
,
258 HdDev
.PartitionStart
+ HdDev
.PartitionSize
- 1,
260 ((Mbr
->Partition
[Index
].OSIndicator
== EFI_PARTITION
) ? &gEfiPartTypeSystemPartGuid
: NULL
)
263 if (!EFI_ERROR (Status
)) {
269 // It's an extended partition. Follow the extended partition
270 // chain to get all the logical drives
273 ExtMbrStartingLba
= 0;
276 Status
= DiskIo
->ReadDisk (
279 MultU64x32 (ExtMbrStartingLba
, BlockSize
),
283 if (EFI_ERROR (Status
)) {
288 if (UNPACK_UINT32 (Mbr
->Partition
[0].SizeInLBA
) == 0) {
292 if ((Mbr
->Partition
[0].OSIndicator
== EXTENDED_DOS_PARTITION
) ||
293 (Mbr
->Partition
[0].OSIndicator
== EXTENDED_WINDOWS_PARTITION
))
295 ExtMbrStartingLba
= UNPACK_UINT32 (Mbr
->Partition
[0].StartingLBA
);
297 // A value of 0 is invalid for StartingLBA
299 if (ExtMbrStartingLba
== 0) {
306 HdDev
.PartitionNumber
= ++Index
;
307 HdDev
.PartitionStart
= UNPACK_UINT32 (Mbr
->Partition
[0].StartingLBA
) + ExtMbrStartingLba
+ ParentHdDev
.PartitionStart
;
308 HdDev
.PartitionSize
= UNPACK_UINT32 (Mbr
->Partition
[0].SizeInLBA
);
309 if ((HdDev
.PartitionStart
+ HdDev
.PartitionSize
- 1 >= ParentHdDev
.PartitionStart
+ ParentHdDev
.PartitionSize
) ||
310 (HdDev
.PartitionStart
<= ParentHdDev
.PartitionStart
))
316 // The signature in EBR(Extended Boot Record) should always be 0.
318 *((UINT32
*)&HdDev
.Signature
[0]) = 0;
320 ZeroMem (&PartitionInfo
, sizeof (EFI_PARTITION_INFO_PROTOCOL
));
321 PartitionInfo
.Revision
= EFI_PARTITION_INFO_PROTOCOL_REVISION
;
322 PartitionInfo
.Type
= PARTITION_TYPE_MBR
;
323 if (Mbr
->Partition
[0].OSIndicator
== EFI_PARTITION
) {
324 PartitionInfo
.System
= 1;
327 CopyMem (&PartitionInfo
.Info
.Mbr
, &Mbr
->Partition
[0], sizeof (MBR_PARTITION_RECORD
));
329 Status
= PartitionInstallChildHandle (
337 (EFI_DEVICE_PATH_PROTOCOL
*)&HdDev
,
339 HdDev
.PartitionStart
- ParentHdDev
.PartitionStart
,
340 HdDev
.PartitionStart
- ParentHdDev
.PartitionStart
+ HdDev
.PartitionSize
- 1,
342 ((Mbr
->Partition
[0].OSIndicator
== EFI_PARTITION
) ? &gEfiPartTypeSystemPartGuid
: NULL
)
344 if (!EFI_ERROR (Status
)) {
348 if ((Mbr
->Partition
[1].OSIndicator
!= EXTENDED_DOS_PARTITION
) &&
349 (Mbr
->Partition
[1].OSIndicator
!= EXTENDED_WINDOWS_PARTITION
)
355 ExtMbrStartingLba
= UNPACK_UINT32 (Mbr
->Partition
[1].StartingLBA
);
357 // Don't allow partition to be self referencing
359 if (ExtMbrStartingLba
== 0) {
362 } while (ExtMbrStartingLba
< ParentHdDev
.PartitionSize
);