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