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