]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Disk/PartitionDxe/Mbr.c
MdeModulePkg/PartitionDxe: Skip the MBR that add for CD-ROM
[mirror_edk2.git] / MdeModulePkg / Universal / Disk / PartitionDxe / Mbr.c
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 {
39 UINT32 StartingLBA;
40 UINT32 EndingLBA;
41 UINT32 NewEndingLBA;
42 UINT32 SizeInLBA;
43 INTN Index1;
44 INTN Index2;
45 BOOLEAN MbrValid;
46
47 if (Mbr->Signature != MBR_SIGNATURE) {
48 return FALSE;
49 }
50 //
51 // The BPB also has this signature, so it can not be used alone.
52 //
53 MbrValid = FALSE;
54 for (Index1 = 0; Index1 < MAX_MBR_PARTITIONS; Index1++) {
55 StartingLBA = UNPACK_UINT32 (Mbr->Partition[Index1].StartingLBA);
56 SizeInLBA = UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA);
57
58 //
59 // If the MBR with partition entry covering the ENTIRE disk, i.e. start at LBA0
60 // with whole disk size, we treat it as an invalid MBR partition.
61 //
62 if ((StartingLBA == 0) &&
63 (SizeInLBA == (LastLba + 1))) {
64 //
65 // Refer to the http://manpages.ubuntu.com/manpages/bionic/man8/mkudffs.8.html
66 // "WHOLE DISK VS PARTITION"
67 // Some linux ISOs may put the MBR table in the first 512 bytes for compatibility reasons with Windows.
68 // Linux kernel ignores MBR table if contains partition which starts at sector 0.
69 // Skip it because we don't have the partition check for UDF(El Torito compatible).
70 // It would continue to do the whole disk check in the UDF routine.
71 //
72 DEBUG ((DEBUG_INFO, "PartitionValidMbr: MBR table has partition entry covering the ENTIRE disk. Don't treat it as a valid MBR.\n"));
73
74 return FALSE;
75 }
76
77 if (Mbr->Partition[Index1].OSIndicator == 0x00 || SizeInLBA == 0) {
78 continue;
79 }
80
81 MbrValid = TRUE;
82 EndingLBA = StartingLBA + SizeInLBA - 1;
83 if (EndingLBA > LastLba) {
84 //
85 // Compatibility Errata:
86 // Some systems try to hide drive space with their INT 13h driver
87 // This does not hide space from the OS driver. This means the MBR
88 // that gets created from DOS is smaller than the MBR created from
89 // a real OS (NT & Win98). This leads to BlockIo->LastBlock being
90 // wrong on some systems FDISKed by the OS.
91 //
92 // return FALSE since no block devices on a system are implemented
93 // with INT 13h
94 //
95
96 DEBUG((EFI_D_INFO, "PartitionValidMbr: Bad MBR partition size EndingLBA(%1x) > LastLBA(%1x)\n", EndingLBA, LastLba));
97
98 return FALSE;
99 }
100
101 for (Index2 = Index1 + 1; Index2 < MAX_MBR_PARTITIONS; Index2++) {
102 StartingLBA = UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA);
103 SizeInLBA = UNPACK_UINT32 (Mbr->Partition[Index2].SizeInLBA);
104
105 if (Mbr->Partition[Index2].OSIndicator == 0x00 || SizeInLBA == 0) {
106 continue;
107 }
108
109 NewEndingLBA = StartingLBA + SizeInLBA - 1;
110 if (NewEndingLBA >= StartingLBA && StartingLBA <= EndingLBA) {
111 //
112 // This region overlaps with the Index1'th region
113 //
114 return FALSE;
115 }
116 }
117 }
118 //
119 // None of the regions overlapped so MBR is O.K.
120 //
121 return MbrValid;
122 }
123
124
125 /**
126 Install child handles if the Handle supports MBR format.
127
128 @param[in] This Calling context.
129 @param[in] Handle Parent Handle.
130 @param[in] DiskIo Parent DiskIo interface.
131 @param[in] DiskIo2 Parent DiskIo2 interface.
132 @param[in] BlockIo Parent BlockIo interface.
133 @param[in] BlockIo2 Parent BlockIo2 interface.
134 @param[in] DevicePath Parent Device Path.
135
136 @retval EFI_SUCCESS A child handle was added.
137 @retval EFI_MEDIA_CHANGED Media change was detected.
138 @retval Others MBR partition was not found.
139
140 **/
141 EFI_STATUS
142 PartitionInstallMbrChildHandles (
143 IN EFI_DRIVER_BINDING_PROTOCOL *This,
144 IN EFI_HANDLE Handle,
145 IN EFI_DISK_IO_PROTOCOL *DiskIo,
146 IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
147 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
148 IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
149 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
150 )
151 {
152 EFI_STATUS Status;
153 MASTER_BOOT_RECORD *Mbr;
154 UINT32 ExtMbrStartingLba;
155 UINT32 Index;
156 HARDDRIVE_DEVICE_PATH HdDev;
157 HARDDRIVE_DEVICE_PATH ParentHdDev;
158 EFI_STATUS Found;
159 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
160 EFI_DEVICE_PATH_PROTOCOL *LastDevicePathNode;
161 UINT32 BlockSize;
162 UINT32 MediaId;
163 EFI_LBA LastSector;
164 EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
165
166 Found = EFI_NOT_FOUND;
167
168 BlockSize = BlockIo->Media->BlockSize;
169 MediaId = BlockIo->Media->MediaId;
170 LastSector = DivU64x32 (
171 MultU64x32 (BlockIo->Media->LastBlock + 1, BlockSize),
172 MBR_SIZE
173 ) - 1;
174
175 //
176 // Ensure the block size can hold the MBR
177 //
178 if (BlockSize < sizeof (MASTER_BOOT_RECORD)) {
179 return EFI_NOT_FOUND;
180 }
181
182 Mbr = AllocatePool (BlockSize);
183 if (Mbr == NULL) {
184 return Found;
185 }
186
187 Status = DiskIo->ReadDisk (
188 DiskIo,
189 MediaId,
190 0,
191 BlockSize,
192 Mbr
193 );
194 if (EFI_ERROR (Status)) {
195 Found = Status;
196 goto Done;
197 }
198 if (!PartitionValidMbr (Mbr, LastSector)) {
199 goto Done;
200 }
201 //
202 // We have a valid mbr - add each partition
203 //
204 //
205 // Get starting and ending LBA of the parent block device.
206 //
207 LastDevicePathNode = NULL;
208 ZeroMem (&ParentHdDev, sizeof (ParentHdDev));
209 DevicePathNode = DevicePath;
210 while (!IsDevicePathEnd (DevicePathNode)) {
211 LastDevicePathNode = DevicePathNode;
212 DevicePathNode = NextDevicePathNode (DevicePathNode);
213 }
214
215 if (LastDevicePathNode != NULL) {
216 if (DevicePathType (LastDevicePathNode) == MEDIA_DEVICE_PATH &&
217 DevicePathSubType (LastDevicePathNode) == MEDIA_HARDDRIVE_DP
218 ) {
219 CopyMem (&ParentHdDev, LastDevicePathNode, sizeof (ParentHdDev));
220 } else {
221 LastDevicePathNode = NULL;
222 }
223 }
224
225 ZeroMem (&HdDev, sizeof (HdDev));
226 HdDev.Header.Type = MEDIA_DEVICE_PATH;
227 HdDev.Header.SubType = MEDIA_HARDDRIVE_DP;
228 SetDevicePathNodeLength (&HdDev.Header, sizeof (HdDev));
229 HdDev.MBRType = MBR_TYPE_PCAT;
230 HdDev.SignatureType = SIGNATURE_TYPE_MBR;
231
232 if (LastDevicePathNode == NULL) {
233 //
234 // This is a MBR, add each partition
235 //
236 for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
237 if (Mbr->Partition[Index].OSIndicator == 0x00 || UNPACK_UINT32 (Mbr->Partition[Index].SizeInLBA) == 0) {
238 //
239 // Don't use null MBR entries
240 //
241 continue;
242 }
243
244 if (Mbr->Partition[Index].OSIndicator == PMBR_GPT_PARTITION) {
245 //
246 // This is the guard MBR for the GPT. If you ever see a GPT disk with zero partitions you can get here.
247 // We can not produce an MBR BlockIo for this device as the MBR spans the GPT headers. So formating
248 // this BlockIo would corrupt the GPT structures and require a recovery that would corrupt the format
249 // that corrupted the GPT partition.
250 //
251 continue;
252 }
253
254 HdDev.PartitionNumber = Index + 1;
255 HdDev.PartitionStart = UNPACK_UINT32 (Mbr->Partition[Index].StartingLBA);
256 HdDev.PartitionSize = UNPACK_UINT32 (Mbr->Partition[Index].SizeInLBA);
257 CopyMem (HdDev.Signature, &(Mbr->UniqueMbrSignature[0]), sizeof (Mbr->UniqueMbrSignature));
258
259 ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
260 PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
261 PartitionInfo.Type = PARTITION_TYPE_MBR;
262 if (Mbr->Partition[Index].OSIndicator == EFI_PARTITION) {
263 PartitionInfo.System = 1;
264 }
265 CopyMem (&PartitionInfo.Info.Mbr, &Mbr->Partition[Index], sizeof (MBR_PARTITION_RECORD));
266
267 Status = PartitionInstallChildHandle (
268 This,
269 Handle,
270 DiskIo,
271 DiskIo2,
272 BlockIo,
273 BlockIo2,
274 DevicePath,
275 (EFI_DEVICE_PATH_PROTOCOL *) &HdDev,
276 &PartitionInfo,
277 HdDev.PartitionStart,
278 HdDev.PartitionStart + HdDev.PartitionSize - 1,
279 MBR_SIZE,
280 ((Mbr->Partition[Index].OSIndicator == EFI_PARTITION) ? &gEfiPartTypeSystemPartGuid: NULL)
281 );
282
283 if (!EFI_ERROR (Status)) {
284 Found = EFI_SUCCESS;
285 }
286 }
287 } else {
288 //
289 // It's an extended partition. Follow the extended partition
290 // chain to get all the logical drives
291 //
292 Index = 0;
293 ExtMbrStartingLba = 0;
294
295 do {
296
297 Status = DiskIo->ReadDisk (
298 DiskIo,
299 MediaId,
300 MultU64x32 (ExtMbrStartingLba, BlockSize),
301 BlockSize,
302 Mbr
303 );
304 if (EFI_ERROR (Status)) {
305 Found = Status;
306 goto Done;
307 }
308
309 if (UNPACK_UINT32 (Mbr->Partition[0].SizeInLBA) == 0) {
310 break;
311 }
312
313 if ((Mbr->Partition[0].OSIndicator == EXTENDED_DOS_PARTITION) ||
314 (Mbr->Partition[0].OSIndicator == EXTENDED_WINDOWS_PARTITION)) {
315 ExtMbrStartingLba = UNPACK_UINT32 (Mbr->Partition[0].StartingLBA);
316 continue;
317 }
318 HdDev.PartitionNumber = ++Index;
319 HdDev.PartitionStart = UNPACK_UINT32 (Mbr->Partition[0].StartingLBA) + ExtMbrStartingLba + ParentHdDev.PartitionStart;
320 HdDev.PartitionSize = UNPACK_UINT32 (Mbr->Partition[0].SizeInLBA);
321 if ((HdDev.PartitionStart + HdDev.PartitionSize - 1 >= ParentHdDev.PartitionStart + ParentHdDev.PartitionSize) ||
322 (HdDev.PartitionStart <= ParentHdDev.PartitionStart)) {
323 break;
324 }
325
326 //
327 // The signature in EBR(Extended Boot Record) should always be 0.
328 //
329 *((UINT32 *) &HdDev.Signature[0]) = 0;
330
331 ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
332 PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
333 PartitionInfo.Type = PARTITION_TYPE_MBR;
334 if (Mbr->Partition[0].OSIndicator == EFI_PARTITION) {
335 PartitionInfo.System = 1;
336 }
337 CopyMem (&PartitionInfo.Info.Mbr, &Mbr->Partition[0], sizeof (MBR_PARTITION_RECORD));
338
339 Status = PartitionInstallChildHandle (
340 This,
341 Handle,
342 DiskIo,
343 DiskIo2,
344 BlockIo,
345 BlockIo2,
346 DevicePath,
347 (EFI_DEVICE_PATH_PROTOCOL *) &HdDev,
348 &PartitionInfo,
349 HdDev.PartitionStart - ParentHdDev.PartitionStart,
350 HdDev.PartitionStart - ParentHdDev.PartitionStart + HdDev.PartitionSize - 1,
351 MBR_SIZE,
352 ((Mbr->Partition[0].OSIndicator == EFI_PARTITION) ? &gEfiPartTypeSystemPartGuid: NULL)
353 );
354 if (!EFI_ERROR (Status)) {
355 Found = EFI_SUCCESS;
356 }
357
358 if ((Mbr->Partition[1].OSIndicator != EXTENDED_DOS_PARTITION) &&
359 (Mbr->Partition[1].OSIndicator != EXTENDED_WINDOWS_PARTITION)
360 ) {
361 break;
362 }
363
364 ExtMbrStartingLba = UNPACK_UINT32 (Mbr->Partition[1].StartingLBA);
365 //
366 // Don't allow partition to be self referencing
367 //
368 if (ExtMbrStartingLba == 0) {
369 break;
370 }
371 } while (ExtMbrStartingLba < ParentHdDev.PartitionSize);
372 }
373
374 Done:
375 FreePool (Mbr);
376
377 return Found;
378 }