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